
Wie die Sicherheitsexperten von Trail of Bits berichten, ist die Testabdeckung eine unzuverlässige Kennzahl. Sie zeigt lediglich, ob Code während eines Tests ausgeführt wurde – nicht jedoch, ob seine Korrektheit tatsächlich überprüft wurde. Selbst eine Testsuite mit 100 Prozent Abdeckung kann kritische Schwachstellen übersehen.
Gerade in der Blockchain-Entwicklung, wo Fehler Verluste in Millionenhöhe verursachen können, erweist sich das trügerische Sicherheitsgefühl einer „hohen Abdeckung“ als riskant. Wenn Millionen oder gar Milliarden von Dollar auf dem Spiel stehen, reicht ein „ausreichender“ Test nicht aus.
Mutationstests als Werkzeug gegen blinde Flecken
Statt sich ausschließlich auf Abdeckungsmetriken zu verlassen, sollten Entwickler ihre Tests selbst auf den Prüfstand stellen. Genau hier setzt das Mutationstesten an: Die Technik führt gezielt Fehler in den Code ein und prüft, ob die Tests diese erkennen. Trail of Bits nutzt diese Methode regelmäßig in Audits – mit großem Erfolg.
Ein Beispiel liefert das Arkis-Protokoll: Dort konnte ein Mutationstest eine gravierende Schwachstelle aufdecken, die konventionelle Tests übersehen hatten. Angreifer hätten dadurch Gelder abziehen können. Der Fall zeigt, wie wertvoll Mutationstests sind, um ähnliche versteckte Risiken frühzeitig zu erkennen – bevor sie von Angreifern ausgenutzt werden.
Die Rolle von Tests im Blockchain-Entwicklungsprozess
Tests sind ein zentrales Instrument der Blockchain-Entwicklung. Sie überprüfen, ob Funktionen und Abläufe korrekt umgesetzt sind, ob Zugriffskontrollen greifen, wie Verträge unter Stress reagieren und ob Änderungen unerwünschte Nebeneffekte verursachen.
Besonders bewährt haben sich drei Testmethoden:
-
Unit-Tests: Sie prüfen die kleinsten funktionalen Einheiten des Codes, etwa einzelne Funktionen oder Randfälle. Eine robuste Unit-Test-Suite erleichtert die Weiterentwicklung und dient als Basis für Integrationstests.
-
Integrationstests: Sie simulieren Interaktionen zwischen Funktionen und Verträgen sowie komplette Benutzerabläufe. So lassen sich Probleme bei Datenvalidierung, Zugriffskontrollen und Vertragslogik identifizieren.
-
Fuzz-Tests: Sie erzeugen zufällige Sequenzen von Interaktionen mit Verträgen oder Funktionen. Das Ergebnis wird gegen unveränderliche Bedingungen geprüft. Damit lassen sich unter anderem Fehler bei mathematischen Funktionen, fehlerhafte Datenkodierung oder Probleme bei der Persistenz erkennen.
Wie man die Effektivität einer Testsuite misst
Wenn Sie im Jahr 2025 ein Blockchain-Protokoll entwickeln, sollten mindestens alle drei Methoden zum Einsatz kommen. Die Tatsache, dass Sie alle drei Methoden verwenden, bedeutet jedoch nicht automatisch, dass Sie diese auch effektiv einsetzen, um Fehler tatsächlich zu finden.
Die gängigste Kennzahl für die Effektivität einer Testsuite ist die sogenannte „Abdeckung”. Die Abdeckung misst, wie viel Ihres Codes von Ihrer Testsuite „berührt” wird. Der gesunde Menschenverstand sagt uns, dass eine Testsuite, um gut zu sein, 100 % Ihres Codes abdecken sollte – das heißt, 100 % aller Zeilen/Verzweigungen sollten von Tests berührt werden.
In der Regel ist es schwierig und ressourcenintensiv, eine 100-prozentige Codeabdeckung zu erreichen. Bei den meisten Softwareentwicklungsprojekten gilt eine Abdeckung von 80 % als „ausreichend“, aber angesichts der mit Blockchain verbundenen Risiken und finanziellen Anreize ist dies für Verträge definitiv nicht ausreichend.
Und selbst wenn Ihre Testsuite Ihren gesamten Code abdeckt, können Sie dann sicher sein, dass Ihr System sicher ist? Die Antwort kennen Sie wahrscheinlich schon – sie lautet „nein“. Einer der größten Nachteile der Verwendung der Abdeckung zur Bewertung Ihrer Testsuite besteht darin, dass eine 100-prozentige Abdeckung nicht bedeutet, dass alle legitimen und böswilligen Anwendungsfälle getestet werden.
Lassen Sie uns anhand eines sehr einfachen Beispiels zeigen, wie irreführend Abdeckungsmetriken sein können. Unten haben wir eine verifyMinimumDeposit()-Funktion, die true zurückgibt, wenn der eingezahlte Betrag mindestens 1 Ether beträgt, und andernfalls false:
Grafik Quelle: Trail of Bits
Der Entwickler hat zwei Unit-Tests für die Funktion erstellt, um die Rückgabewerte true und false zu testen:
Die Testabdeckung für die Funktion verifyMinimumDeposit() beträgt 100 %, da alle Zeilen und Verzweigungen abgedeckt sind. Der Entwickler ist mit der Metrik zufrieden und beendet seine Arbeit für heute. Die Tests sind jedoch fehlerhaft: Es gibt keine Testfälle, die Randwerte überprüfen. Wenn beispielsweise durch eine Code-Umgestaltung versehentlich die Bedingung in deposit >= 2 ether geändert wird, werden die Tests weiterhin bestanden, aber die grundlegende Protokollfunktionalität wird beeinträchtigt. Die Testsuite hat den falschen Wert nicht erkannt, und abhängig von anderen Faktoren könnte der neue Code sogar ein Sicherheitsrisiko darstellen.
Sie sehen also, dass die Abdeckung nicht die beste Metrik zur Bewertung der Wirksamkeit einer Testsuite ist. Ein besserer Ansatz ist die Verwendung von Mutationstests, einer Technik zum Auffinden von Lücken in der Testsuite-Abdeckung, die nicht mit der tatsächlichen Zeilen- oder Verzweigungsabdeckung zusammenhängen.
Mutationsprüfung
Auf hoher Ebene nimmt eine Mutationsprüfung geringfügige systematische Änderungen an der Codebasis vor und führt die vorhandene Testsuite für den geänderten Code aus. Jede geänderte Version der Codebasis wird als „Mutante” bezeichnet.
Nachdem die Testsuite auf einen Mutanten angewendet wurde, gibt es zwei mögliche Ergebnisse: Wenn die Testsuite fehlschlägt, wird der Mutant „gefangen“ oder „getötet“, was bedeutet, dass die Testsuite Überprüfungen für diese bestimmte Änderung enthält. Wenn die Testsuite jedoch korrekt abgeschlossen wird, wurde der Mutant nicht gefangen (er hat „überlebt“), was eine Lücke in der Abdeckung der Testsuite aufzeigt.
Das Ziel einer Mutationstestkampagne ist es, so viele Mutanten wie möglich zu generieren und zu überprüfen, ob die Testsuite alle Mutanten fangen kann. Eine nützliche Kennzahl zur Bewertung der Effektivität der Testsuite ist der Prozentsatz der gefangenen Mutanten im Verhältnis zu allen generierten Mutanten. Im Idealfall sollte dieser Wert 100 % betragen, was bedeutet, dass die Testsuite alle generierten Mutanten töten konnte.
Im Folgenden sind einige gängige Mutationen aufgeführt, die an einer Codebasis durchgeführt werden können:
- Ersetzen von unären oder binären Operatoren, z. B. Ersetzen einer Addition durch eine Subtraktion
- Ersetzen von Zuweisungsoperatoren, z. B. Ersetzen von
+=durch= - Ersetzen von konstanten Literalwerten, z. B. Ersetzen aller Konstanten ungleich Null durch
0 - Negieren oder Ersetzen von Bedingungen in
if-Anweisungen oder Schleifen - Auskommentieren ganzer Codezeilen
- Ersetzen von Zeilen durch die Anweisung „revert“
- Ersetzen von Datentypen, z. B. Ersetzen von
int128durchint64
Der größte Nachteil von Mutationstests besteht darin, dass eine Kampagne sehr lange dauern kann: Für jede neu generierte Mutation muss der gesamte Kompilierungs- und Testprozess durchlaufen werden. Eine Strategie zur Verkürzung der Ausführungszeit besteht darin, die Mutationen in Prioritätsgruppen zu unterteilen und Mutationen mit niedrigerer Priorität zu überspringen, wenn Mutationen mit höherer Priorität überleben. Wenn beispielsweise eine auskommentierte Codezeile nicht erfasst wird, führt die Änderung eines Additionsoperators in dieser Zeile wahrscheinlich ebenfalls zu einer überlebenden Mutation.
Nach der Durchführung einer Kampagne müssen die Ergebnisse analysiert werden. Überlebende Mutanten deuten auf Lücken in der Testabdeckung und möglicherweise auf ein verstecktes Sicherheitsrisiko hin. Die Ermittlung der Ursache ist wichtig, um die Auswirkungen und die empfohlene Lösung für das Problem zu bestimmen.
Automatisierte Mutationstests
Seit Version 0.10.2 unterstützt Slither nativ Mutationstests für Solidity-Codebasen über slither-mutate, ein Befehlszeilentool, das den Prozess der Generierung von Mutanten, deren Auswertung und die Erstellung eines Berichts mit den überlebenden Mutationen automatisiert.
Um Ihre eigene Mutationskampagne zu starten, laden Sie einfach die neueste Version von Slither herunter und führen Sie diesen Befehl aus:
slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results)
Dieser Befehl ist speziell für Codebasen gedacht, die das Foundry-Framework zum Testen verwenden. Wenn Sie Foundry nicht verwenden, ersetzen Sie den Inhalt von --test-cmd durch die Anweisungen, die zum Ausführen der Testsuite erforderlich sind.
Es stehen mehrere weitere Befehlszeilenoptionen zur Verfügung. Um mehr über diese Optionen zu erfahren, führen Sie diesen Befehl aus:
slither-mutate --help
Nach Abschluss der Kampagne erhalten Sie einen Bericht mit allen nicht erfassten Mutanten und einigen Kennzahlen zur Kampagne. Eine Kopie dieser Mutanten ist im Ausgabeverzeichnis verfügbar, das standardmäßig ./mutation_campaign lautet.
Die Ausgabe wird im folgenden Format dargestellt:
INFO:Slither-Mutate:Mutating contractContractName
INFO:Slither-Mutate:[Mutator] Line FileLine: ‚original line‘ ==> ‚mutated line‘ --> UNCAUGHT
Dies ist ein Beispiel für einen nicht gefundenen Mutanten in Zeile FileLine des Vertrags ContractName. Wenn Sie die ursprüngliche Zeile durch die mutierte Zeile ersetzen, wird die Testsuite ausgeführt und erkennt keine Testfehler. Es stehen mehrere Mutatoren zur Verfügung, von denen jeder einen eindeutigen Alias hat. Beispielsweise lautet Mutator „CR“, wenn eine Mutation vom Mutator „Comment Replacement“ (Kommentarersetzung) erkannt wird, der ganze Zeilen auskommentiert. slither-mutate --list-mutators zeigt die vollständige Liste der verfügbaren Mutatoren und ihrer Aliase an.
Wie bereits erwähnt, kann die Ausführung einer Mutationstestkampagne mehrere Stunden oder Tage dauern, je nach Größe der Codebasis, der Anzahl der für die Mutation ausgewählten Verträge, den aktivierten Mutatoren und der Laufzeit der Testsuite.
Fallstudie
Um zu zeigen, wie effektiv Mutationstests sein können, betrachten wir die Prüfung des Arkis-Protokolls durch Trail of Bits. Während der Prüfung führten unsere Ingenieure eine Mutationstestkampagne für die betroffenen Dateien durch und fanden mehrere unentdeckte Mutationen, was zur Entdeckung von TOB-ARK-10 führte, einem schwerwiegenden Problem, das es Angreifern ermöglicht hätte, Gelder aus dem Protokoll abzuziehen.
Das Problem ist auf eine fehlende Validierung eines vom Benutzer bereitgestellten Parameters zurückzuführen. Anstatt die Menge der übertragenen Token zu validieren, vertraut die Funktion blind dem Parameter _cmd, der von einem Angreifer manipuliert werden kann.
Abbildung C.2 in Anhang C des Berichts zeigt einen Teil der Ausgabe von slither-mutate:
INFO:Slither-Mutate:[CR] Zeile 33: ‚cmdsToExecute.last().value = _cmd.value‘ ==> ‚//cmdsToExecute.last().value = _cmd.value‘ --> UNCAUGHT
Diese Ergebnisse zeigen, dass die Testabdeckung für die betroffenen Dateien unzureichend war: Das Auskommentieren von Zeile 33 hatte keine Auswirkungen auf die Tests. Nach der Analyse der Grundursache haben unsere Ingenieure das Problem entdeckt und gemeldet.
Probleme wie dieses werden oft durch fehlende Überprüfungen des resultierenden Zustands, die Verwendung von Mocks, die nicht die realen Situationen widerspiegeln, oder einfach durch einen Mangel an Testfällen für die jeweilige Funktion verursacht. Bei der Verbesserung der Qualität Ihrer Testsuite geht es nicht nur darum, eine höhere Abdeckung zu erreichen, sondern auch darum, die Testfälle robust und aussagekräftig zu gestalten.
Verwenden Sie Mutationstests in Ihren Projekten
Wenn Sie Blockchain-Entwickler sind, führen Sie eine Mutationstestkampagne durch und verbessern Sie Ihre Testsuite, um alle Mutanten zu beseitigen. Als Belohnung erhalten Sie eine umfassende Testsuite, mit der Sie Probleme frühzeitig im Entwicklungsprozess erkennen können und die Sicherheitsingenieuren hilft, Ihre Codebasis effizienter zu prüfen. Wenn Sie Auditor sind, nehmen Sie Mutationstests in Ihr Toolkit auf und finden Sie die Ursache für überlebende Mutanten. In den meisten Fällen decken sie versteckte Fehler in der Codebasis auf.
Quelle: Trail of Bits
Entdecken Sie mehr
Bild/Quelle: https://depositphotos.com/de/home.html
Fachartikel

Cyber-Angriff auf Next.js: 59.000 Server in 48 Stunden kompromittiert

Windows RasMan DoS-Lücke: 0patch bietet kostenlosen Schutz vor aktuellem 0-Day

Schwachstellen in Eurostar-KI-Chatbot aufgedeckt

Cyberkriminelle zahlen bis zu 15.000 Dollar für Insider-Zugang zu Unternehmenssystemen

Wenn KI-Detektoren versagen: Code-Verschleierung entlarvt Schwächen großer Sprachmodelle
Studien
![Featured image for “Phishing-Studie deckt auf: [EXTERN]-Markierung schützt Klinikpersonal kaum”](https://www.all-about-security.de/wp-content/uploads/2025/12/phishing-4.jpg)
Phishing-Studie deckt auf: [EXTERN]-Markierung schützt Klinikpersonal kaum

Gartner-Umfrage: Mehrheit der nicht geschäftsführenden Direktoren zweifelt am wirtschaftlichen Wert von Cybersicherheit

49 Prozent der IT-Verantwortlichen in Sicherheitsirrtum

Deutschland im Glasfaserausbau international abgehängt

NIS2 kommt – Proliance-Studie zeigt die Lage im Mittelstand
Whitepaper

State of Cloud Security Report 2025: Cloud-Angriffsfläche wächst schnell durch KI

BITMi zum Gutachten zum Datenzugriff von US-Behörden: EU-Unternehmen als Schlüssel zur Datensouveränität

Agentic AI als Katalysator: Wie die Software Defined Industry die Produktion revolutioniert

OWASP veröffentlicht Security-Framework für autonome KI-Systeme

Malware in Bewegung: Wie animierte Köder Nutzer in die Infektionsfalle locken
Hamsterrad-Rebell

Platform Security: Warum ERP-Systeme besondere Sicherheitsmaßnahmen erfordern

Daten in eigener Hand: Europas Souveränität im Fokus

Sicherer Remote-Zugriff (SRA) für Operational Technology (OT) und industrielle Steuerungs- und Produktionssysteme (ICS)

Identity und Access Management (IAM) im Zeitalter der KI-Agenten: Sichere Integration von KI in Unternehmenssysteme









