Smart-Contract-Sicherheit
Smart Contracts sind extrem flexibel und in der Lage, große Mengen an Werten und Daten zu kontrollieren, während sie unveränderliche Logik basierend auf Code ausführen, der auf der Blockchain bereitgestellt wurde. Dies hat ein lebendiges Ökosystem von vertrauenslosen und dezentralen Anwendungen geschaffen, die viele Vorteile gegenüber herkömmlichen Systemen bieten. Sie stellen jedoch auch Gelegenheiten für Angreifer dar, die durch die Ausnutzung von Schwachstellen in Smart Contracts profitieren wollen.
Öffentliche Blockchains wie Ethereum verkomplizieren das Thema der Sicherung von Smart Contracts zusätzlich. Bereitgestellter Vertrags-Code kann normalerweise nicht geändert werden, um Sicherheitslücken zu schließen, während aus Smart Contracts gestohlene Vermögenswerte extrem schwer zu verfolgen und aufgrund der Unveränderlichkeit meist unwiederbringlich sind.
Obwohl die Zahlen variieren, wird geschätzt, dass der Gesamtwert, der aufgrund von Sicherheitsmängeln in Smart Contracts gestohlen wurde oder verloren ging, leicht über 1 Milliarde US-Dollar liegt. Dies umfasst aufsehenerregende Vorfälle wie den DAO-Hack (opens in a new tab) (3,6 Millionen gestohlene ETH, nach heutigen Preisen über 1 Milliarde US-Dollar wert), den Hack der Parity-Multisig-Wallet (opens in a new tab) (30 Millionen US-Dollar an Hacker verloren) und das Problem der eingefrorenen Parity-Wallet (opens in a new tab) (über 300 Millionen US-Dollar in ETH für immer gesperrt).
Die oben genannten Probleme machen es für Entwickler unerlässlich, Aufwand in die Entwicklung sicherer, robuster und widerstandsfähiger Smart Contracts zu investieren. Smart-Contract-Sicherheit ist eine ernste Angelegenheit, und jeder Entwickler tut gut daran, sich damit vertraut zu machen. Dieser Leitfaden behandelt Sicherheitsüberlegungen für Ethereum-Entwickler und untersucht Ressourcen zur Verbesserung der Smart-Contract-Sicherheit.
Voraussetzungen
Stelle sicher, dass du mit den Grundlagen der Smart-Contract-Entwicklung vertraut bist, bevor du dich mit dem Thema Sicherheit befasst.
Richtlinien für die Erstellung sicherer Ethereum-Smart-Contracts
1. Entwerfen Sie angemessene Zugriffskontrollen
In Smart Contracts können Funktionen, die mit public oder external markiert sind, von beliebigen Externally Owned Accounts (EOAs) oder Vertrags-Konten aufgerufen werden. Die Angabe der öffentlichen Sichtbarkeit für Funktionen ist notwendig, wenn Sie möchten, dass andere mit Ihrem Vertrag interagieren. Funktionen, die mit private markiert sind, können jedoch nur von Funktionen innerhalb des Smart Contracts und nicht von externen Konten aufgerufen werden. Jedem Netzwerkteilnehmer Zugriff auf Vertragsfunktionen zu geben, kann Probleme verursachen, insbesondere wenn dies bedeutet, dass jeder sensible Operationen durchführen kann (z. B. das Prägen neuer Token).
Um die unbefugte Nutzung von Smart-Contract-Funktionen zu verhindern, ist es notwendig, sichere Zugriffskontrollen zu implementieren. Zugriffskontrollmechanismen beschränken die Möglichkeit, bestimmte Funktionen in einem Smart Contract zu nutzen, auf genehmigte Entitäten, wie z. B. Konten, die für die Verwaltung des Vertrags verantwortlich sind. Das Ownable-Muster und die rollenbasierte Kontrolle sind zwei nützliche Muster zur Implementierung der Zugriffskontrolle in Smart Contracts:
Ownable-Muster
Beim Ownable-Muster wird während des Vertragserstellungsprozesses eine Adresse als „Eigentümer“ (Owner) des Vertrags festgelegt. Geschützten Funktionen wird ein OnlyOwner-Modifikator zugewiesen, der sicherstellt, dass der Vertrag die Identität der aufrufenden Adresse authentifiziert, bevor die Funktion ausgeführt wird. Aufrufe von geschützten Funktionen von anderen Adressen als dem Vertragseigentümer werden immer rückgängig gemacht (revert), was unerwünschten Zugriff verhindert.
Rollenbasierte Zugriffskontrolle
Die Registrierung einer einzelnen Adresse als Owner in einem Smart Contract birgt das Risiko der Zentralisierung und stellt einen Single Point of Failure dar. Wenn die Kontoschlüssel des Eigentümers kompromittiert werden, können Angreifer den ihm gehörenden Vertrag angreifen. Aus diesem Grund kann die Verwendung eines rollenbasierten Zugriffskontrollmusters mit mehreren administrativen Konten eine bessere Option sein.
Bei der rollenbasierten Zugriffskontrolle wird der Zugriff auf sensible Funktionen auf eine Gruppe vertrauenswürdiger Teilnehmer verteilt. Beispielsweise kann ein Konto für das Prägen von Token verantwortlich sein, während ein anderes Konto Upgrades durchführt oder den Vertrag pausiert. Die dezentrale Zugriffskontrolle auf diese Weise eliminiert Single Points of Failure und reduziert die Vertrauensannahmen für Benutzer.
Verwendung von Multi-Signature-Wallets
Ein weiterer Ansatz zur Implementierung einer sicheren Zugriffskontrolle ist die Verwendung eines Mehrfachsignatur-Kontos zur Verwaltung eines Vertrags. Im Gegensatz zu einem regulären EOA gehören Mehrfachsignatur-Konten mehreren Entitäten und erfordern Signaturen von einer Mindestanzahl von Konten – sagen wir 3 von 5 –, um Transaktionen auszuführen.
Die Verwendung einer Multisig für die Zugriffskontrolle führt eine zusätzliche Sicherheitsebene ein, da Aktionen auf dem Zielvertrag die Zustimmung mehrerer Parteien erfordern. Dies ist besonders nützlich, wenn die Verwendung des Ownable-Musters erforderlich ist, da es für einen Angreifer oder böswilligen Insider schwieriger wird, sensible Vertragsfunktionen für böswillige Zwecke zu manipulieren.
2. Verwenden Sie require()-, assert()- und revert()-Anweisungen, um Vertragsoperationen abzusichern
Wie bereits erwähnt, kann jeder öffentliche Funktionen in Ihrem Smart Contract aufrufen, sobald dieser auf der Blockchain bereitgestellt ist. Da Sie nicht im Voraus wissen können, wie externe Konten mit einem Vertrag interagieren werden, ist es ideal, vor der Bereitstellung interne Schutzmaßnahmen gegen problematische Operationen zu implementieren. Sie können korrektes Verhalten in Smart Contracts erzwingen, indem Sie die Anweisungen require(), assert() und revert() verwenden, um Ausnahmen auszulösen und Zustandsänderungen rückgängig zu machen, wenn die Ausführung bestimmte Anforderungen nicht erfüllt.
require(): require werden zu Beginn von Funktionen definiert und stellen sicher, dass vordefinierte Bedingungen erfüllt sind, bevor die aufgerufene Funktion ausgeführt wird. Eine require kann verwendet werden, um Benutzereingaben zu validieren, Zustandsvariablen zu überprüfen oder die Identität des aufrufenden Kontos zu authentifizieren, bevor mit einer Funktion fortgefahren wird.
assert(): assert() wird verwendet, um interne Fehler zu erkennen und auf Verletzungen von „Invarianten“ in Ihrem Code zu prüfen. Eine Invariante ist eine logische Zusicherung über den Zustand eines Vertrags, die für alle Funktionsausführungen gelten sollte. Ein Beispiel für eine Invariante ist das maximale Gesamtangebot oder der Saldo eines Token-Vertrags. Die Verwendung von assert() stellt sicher, dass Ihr Vertrag niemals einen anfälligen Zustand erreicht, und falls doch, werden alle Änderungen an Zustandsvariablen rückgängig gemacht.
revert(): revert() kann in einer if-else-Anweisung verwendet werden, die eine Ausnahme auslöst, wenn die erforderliche Bedingung nicht erfüllt ist. Der folgende Beispielvertrag verwendet revert(), um die Ausführung von Funktionen abzusichern:
pragma solidity ^0.8.4;
contract VendingMachine {
address owner;
error Unauthorized();
function buy(uint amount) public payable {
if (amount > msg.value / 2 ether)
revert("Not enough Ether provided.");
// Kauf durchführen.
}
function withdraw() public {
if (msg.sender != owner)
revert Unauthorized();
payable(msg.sender).transfer(address(this).balance);
}
}
3. Testen Sie Smart Contracts und überprüfen Sie die Code-Korrektheit
Die Unveränderlichkeit von Code, der in der Ethereum Virtual Machine ausgeführt wird, bedeutet, dass Smart Contracts während der Entwicklungsphase ein höheres Maß an Qualitätsbewertung erfordern. Das ausführliche Testen Ihres Vertrags und die Beobachtung auf unerwartete Ergebnisse wird die Sicherheit erheblich verbessern und Ihre Benutzer langfristig schützen.
Die übliche Methode besteht darin, kleine Unit-Tests mit Mock-Daten zu schreiben, die der Vertrag voraussichtlich von Benutzern erhalten wird. Unit-Testing eignet sich gut, um die Funktionalität bestimmter Funktionen zu testen und sicherzustellen, dass ein Smart Contract wie erwartet funktioniert.
Leider ist Unit-Testing isoliert betrachtet nur minimal effektiv zur Verbesserung der Smart-Contract-Sicherheit. Ein Unit-Test könnte beweisen, dass eine Funktion für Mock-Daten ordnungsgemäß ausgeführt wird, aber Unit-Tests sind nur so effektiv wie die geschriebenen Tests. Dies macht es schwierig, übersehene Randfälle und Schwachstellen zu erkennen, die die Sicherheit Ihres Smart Contracts gefährden könnten.
Ein besserer Ansatz ist die Kombination von Unit-Testing mit eigenschaftsbasiertem Testen, das mittels statischer und dynamischer Analyse durchgeführt wird. Die statische Analyse stützt sich auf Low-Level-Darstellungen wie Kontrollflussgraphen (opens in a new tab) und abstrakte Syntaxbäume (opens in a new tab), um erreichbare Programmzustände und Ausführungspfade zu analysieren. Währenddessen führen dynamische Analysetechniken wie Smart-Contract-Fuzzing (opens in a new tab) Vertragscode mit zufälligen Eingabewerten aus, um Operationen zu erkennen, die Sicherheitseigenschaften verletzen.
Formale Verifikation ist eine weitere Technik zur Überprüfung von Sicherheitseigenschaften in Smart Contracts. Im Gegensatz zu regulären Tests kann die Formale Verifikation die Fehlerfreiheit in einem Smart Contract schlüssig beweisen. Dies wird erreicht, indem eine formale Spezifikation erstellt wird, die die gewünschten Sicherheitseigenschaften erfasst, und bewiesen wird, dass ein formales Modell der Verträge dieser Spezifikation entspricht.
4. Bitten Sie um eine unabhängige Überprüfung Ihres Codes
Nach dem Testen Ihres Vertrags ist es ratsam, andere zu bitten, den Quellcode auf Sicherheitsprobleme zu überprüfen. Tests werden nicht jeden Fehler in einem Smart Contract aufdecken, aber eine unabhängige Überprüfung erhöht die Wahrscheinlichkeit, Schwachstellen zu entdecken.
Audits
Die Beauftragung eines Smart-Contract-Audits ist eine Möglichkeit, eine unabhängige Code-Überprüfung durchzuführen. Auditoren spielen eine wichtige Rolle dabei, sicherzustellen, dass Smart Contracts sicher und frei von Qualitätsmängeln und Designfehlern sind.
Dennoch sollten Sie vermeiden, Audits als Allheilmittel zu betrachten. Smart-Contract-Audits werden nicht jeden Fehler finden und sind meistens darauf ausgelegt, eine zusätzliche Überprüfungsrunde zu bieten, die helfen kann, Probleme zu erkennen, die von Entwicklern während der anfänglichen Entwicklung und beim Testen übersehen wurden. Sie sollten auch Best Practices für die Zusammenarbeit mit Auditoren befolgen, wie z. B. die ordnungsgemäße Dokumentation des Codes und das Hinzufügen von Inline-Kommentaren, um den Nutzen eines Smart-Contract-Audits zu maximieren.
- Tipps & Tricks für Smart-Contract-Audits (opens in a new tab) - @tinchoabbate
- Machen Sie das Beste aus Ihrem Audit (opens in a new tab) - Inference
Bug-Bounties
Die Einrichtung eines Bug-Bounty-Programms ist ein weiterer Ansatz zur Implementierung externer Code-Überprüfungen. Ein Bug-Bounty ist eine finanzielle Belohnung, die an Personen (normalerweise Whitehat-Hacker) vergeben wird, die Schwachstellen in einer Anwendung entdecken.
Bei richtiger Anwendung geben Bug-Bounties Mitgliedern der Hacker-Community einen Anreiz, Ihren Code auf kritische Fehler zu untersuchen. Ein Beispiel aus der Praxis ist der „Infinite Money Bug“, der es einem Angreifer ermöglicht hätte, eine unbegrenzte Menge an Ether auf Optimism (opens in a new tab), einem auf Ethereum laufenden Layer 2-Protokoll, zu erstellen. Glücklicherweise hat ein Whitehat-Hacker den Fehler entdeckt (opens in a new tab) und das Team benachrichtigt, wobei er eine hohe Auszahlung erhielt (opens in a new tab).
Eine nützliche Strategie besteht darin, die Auszahlung eines Bug-Bounty-Programms im Verhältnis zu den auf dem Spiel stehenden Geldern festzulegen. Dieser Ansatz, der als „skalierendes Bug-Bounty (opens in a new tab)“ bezeichnet wird, bietet finanzielle Anreize für Einzelpersonen, Schwachstellen verantwortungsvoll offenzulegen, anstatt sie auszunutzen.
5. Befolgen Sie Best Practices bei der Smart-Contract-Entwicklung
Die Existenz von Audits und Bug-Bounties entbindet Sie nicht von Ihrer Verantwortung, qualitativ hochwertigen Code zu schreiben. Gute Smart-Contract-Sicherheit beginnt mit der Befolgung ordnungsgemäßer Design- und Entwicklungsprozesse:
-
Speichern Sie den gesamten Code in einem Versionskontrollsystem wie Git
-
Nehmen Sie alle Code-Änderungen über Pull-Requests vor
-
Stellen Sie sicher, dass Pull-Requests mindestens einen unabhängigen Prüfer haben – wenn Sie alleine an einem Projekt arbeiten, sollten Sie in Erwägung ziehen, andere Entwickler zu finden und Code-Überprüfungen auszutauschen
-
Verwenden Sie eine Entwicklungsumgebung zum Testen, zur Kompilierung und zur Bereitstellung von Smart Contracts
-
Führen Sie Ihren Code durch grundlegende Code-Analyse-Tools wie Cyfrin Aderyn (opens in a new tab), Mythril und Slither. Idealerweise sollten Sie dies tun, bevor jeder Pull-Request zusammengeführt wird, und die Unterschiede in der Ausgabe vergleichen
-
Stellen Sie sicher, dass Ihr Code fehlerfrei kompiliert wird und der Solidity-Compiler keine Warnungen ausgibt
-
Dokumentieren Sie Ihren Code ordnungsgemäß (unter Verwendung von NatSpec (opens in a new tab)) und beschreiben Sie Details zur Vertragsarchitektur in leicht verständlicher Sprache. Dies erleichtert es anderen, Ihren Code zu prüfen und zu überprüfen.
6. Implementieren Sie robuste Disaster-Recovery-Pläne
Das Entwerfen sicherer Zugriffskontrollen, die Implementierung von Funktionsmodifikatoren und andere Vorschläge können die Smart-Contract-Sicherheit verbessern, aber sie können die Möglichkeit böswilliger Exploits nicht ausschließen. Der Aufbau sicherer Smart Contracts erfordert die „Vorbereitung auf den Fehlerfall“ und einen Fallback-Plan, um effektiv auf Angriffe reagieren zu können. Ein ordnungsgemäßer Disaster-Recovery-Plan umfasst einige oder alle der folgenden Komponenten:
Vertrags-Upgrades
Während Ethereum-Smart-Contracts standardmäßig unveränderlich sind, ist es möglich, durch die Verwendung von Upgrade-Mustern ein gewisses Maß an Veränderbarkeit zu erreichen. Das Upgraden von Verträgen ist in Fällen notwendig, in denen ein kritischer Fehler Ihren alten Vertrag unbrauchbar macht und die Bereitstellung neuer Logik die praktikabelste Option ist.
Mechanismen für Vertrags-Upgrades funktionieren unterschiedlich, aber das „Proxy-Muster“ ist einer der beliebteren Ansätze für das Upgraden von Smart Contracts. Proxy-Muster (opens in a new tab) teilen den Zustand und die Logik einer Anwendung auf zwei Verträge auf. Der erste Vertrag (als ‚Proxy-Contract‘ bezeichnet) speichert Zustandsvariablen (z. B. Benutzersalden), während der zweite Vertrag (als ‚Logik-Vertrag‘ bezeichnet) den Code zur Ausführung von Vertragsfunktionen enthält.
Konten interagieren mit dem Proxy-Contract, der alle Funktionsaufrufe über den Low-Level-Aufruf delegatecall() (opens in a new tab) an den Logik-Vertrag weiterleitet. Im Gegensatz zu einem regulären Nachrichtenaufruf stellt delegatecall() sicher, dass der Code, der an der Adresse des Logik-Vertrags ausgeführt wird, im Kontext des aufrufenden Vertrags ausgeführt wird. Dies bedeutet, dass der Logik-Vertrag immer in den Speicher des Proxys (anstelle seines eigenen Speichers) schreibt und die ursprünglichen Werte von msg.sender und msg.value erhalten bleiben.
Das Delegieren von Aufrufen an den Logik-Vertrag erfordert das Speichern seiner Adresse im Speicher des Proxy-Contracts. Daher ist das Upgraden der Vertragslogik nur eine Frage der Bereitstellung eines weiteren Logik-Vertrags und der Speicherung der neuen Adresse im Proxy-Contract. Da nachfolgende Aufrufe an den Proxy-Contract automatisch an den neuen Logik-Vertrag weitergeleitet werden, hätten Sie den Vertrag „upgegradet“, ohne den Code tatsächlich zu ändern.
Mehr zum Upgraden von Verträgen.
Notstopps
Wie bereits erwähnt, können umfangreiche Audits und Tests unmöglich alle Fehler in einem Smart Contract entdecken. Wenn nach der Bereitstellung eine Schwachstelle in Ihrem Code auftritt, ist das Patchen unmöglich, da Sie den an der Vertragsadresse ausgeführten Code nicht ändern können. Außerdem kann die Implementierung von Upgrade-Mechanismen (z. B. Proxy-Muster) Zeit in Anspruch nehmen (sie erfordern oft die Genehmigung verschiedener Parteien), was Angreifern nur mehr Zeit gibt, um mehr Schaden anzurichten.
Die nukleare Option besteht darin, eine „Notstopp“-Funktion zu implementieren, die Aufrufe an anfällige Funktionen in einem Vertrag blockiert. Notstopps umfassen typischerweise die folgenden Komponenten:
-
Eine globale boolesche Variable, die angibt, ob sich der Smart Contract in einem gestoppten Zustand befindet oder nicht. Diese Variable wird beim Einrichten des Vertrags auf
falsegesetzt, wird aber auftruezurückgesetzt, sobald der Vertrag gestoppt wird. -
Funktionen, die bei ihrer Ausführung auf die boolesche Variable verweisen. Solche Funktionen sind zugänglich, wenn der Smart Contract nicht gestoppt ist, und werden unzugänglich, wenn die Notstopp-Funktion ausgelöst wird.
-
Eine Entität, die Zugriff auf die Notstopp-Funktion hat, welche die boolesche Variable auf
truesetzt. Um böswillige Aktionen zu verhindern, können Aufrufe dieser Funktion auf eine vertrauenswürdige Adresse (z. B. den Vertragseigentümer) beschränkt werden.
Sobald der Vertrag den Notstopp aktiviert, sind bestimmte Funktionen nicht mehr aufrufbar. Dies wird erreicht, indem ausgewählte Funktionen in einen Modifikator gewickelt werden, der auf die globale Variable verweist. Unten finden Sie ein Beispiel (opens in a new tab), das eine Implementierung dieses Musters in Verträgen beschreibt:
// Dieser Code wurde nicht professionell geprüft und macht keine Zusagen bezüglich Sicherheit oder Korrektheit. Nutzung auf eigene Gefahr.
contract EmergencyStop {
bool isStopped = false;
modifier stoppedInEmergency {
require(!isStopped);
_;
}
modifier onlyWhenStopped {
require(isStopped);
_;
}
modifier onlyAuthorized {
// Hier die Autorisierung von msg.sender prüfen
_;
}
function stopContract() public onlyAuthorized {
isStopped = true;
}
function resumeContract() public onlyAuthorized {
isStopped = false;
}
function deposit() public payable stoppedInEmergency {
// Hier findet die Einzahlungslogik statt
}
function emergencyWithdraw() public onlyWhenStopped {
// Hier findet die Notabhebung statt
}
}
Dieses Beispiel zeigt die grundlegenden Merkmale von Notstopps:
-
isStoppedist ein boolescher Wert, der zu Beginnfalseist undtruewird, wenn der Vertrag in den Notfallmodus wechselt. -
Die Funktionsmodifikatoren
onlyWhenStoppedundstoppedInEmergencyüberprüfen die VariableisStopped.stoppedInEmergencywird verwendet, um Funktionen zu steuern, die unzugänglich sein sollten, wenn der Vertrag anfällig ist (z. B.deposit()). Aufrufe dieser Funktionen werden einfach rückgängig gemacht.
onlyWhenStopped wird für Funktionen verwendet, die während eines Notfalls aufrufbar sein sollten (z. B. emergencyWithdraw()). Solche Funktionen können helfen, die Situation zu lösen, daher ihr Ausschluss aus der Liste der „eingeschränkten Funktionen“.
Die Verwendung einer Notstopp-Funktionalität bietet eine effektive Übergangslösung für den Umgang mit schwerwiegenden Schwachstellen in Ihrem Smart Contract. Es erhöht jedoch die Notwendigkeit für Benutzer, darauf zu vertrauen, dass Entwickler sie nicht aus eigennützigen Gründen aktivieren. Zu diesem Zweck sind die Dezentralisierung der Kontrolle über den Notstopp, indem er einem Onchain-Abstimmungsmechanismus, einem Timelock oder der Genehmigung durch eine Multisig-Wallet unterworfen wird, mögliche Lösungen.
Ereignisüberwachung
Ereignisse (opens in a new tab) ermöglichen es Ihnen, Aufrufe von Smart-Contract-Funktionen zu verfolgen und Änderungen an Zustandsvariablen zu überwachen. Es ist ideal, Ihren Smart Contract so zu programmieren, dass er ein Ereignis ausgibt, wann immer eine Partei eine sicherheitskritische Aktion durchführt (z. B. das Abheben von Geldern).
Das Protokollieren von Ereignissen und deren offchain-Überwachung bietet Einblicke in Vertragsoperationen und hilft bei der schnelleren Erkennung böswilliger Aktionen. Dies bedeutet, dass Ihr Team schneller auf Hacks reagieren und Maßnahmen ergreifen kann, um die Auswirkungen auf die Benutzer zu mindern, wie z. B. das Pausieren von Funktionen oder die Durchführung eines Upgrades.
Sie können sich auch für ein handelsübliches Überwachungstool entscheiden, das automatisch Warnungen weiterleitet, wenn jemand mit Ihren Verträgen interagiert. Diese Tools ermöglichen es Ihnen, benutzerdefinierte Warnungen basierend auf verschiedenen Auslösern zu erstellen, wie z. B. Transaktionsvolumen, Häufigkeit von Funktionsaufrufen oder den spezifisch beteiligten Funktionen. Beispielsweise könnten Sie eine Warnung programmieren, die eingeht, wenn der in einer einzelnen Transaktion abgehobene Betrag einen bestimmten Schwellenwert überschreitet.
7. Entwerfen Sie sichere Governance-Systeme
Möglicherweise möchten Sie Ihre Anwendung dezentralisieren, indem Sie die Kontrolle über zentrale Smart Contracts an Community-Mitglieder übergeben. In diesem Fall wird das Smart-Contract-System ein Governance-Modul enthalten – einen Mechanismus, der es Community-Mitgliedern ermöglicht, administrative Aktionen über ein Onchain-Governance-System zu genehmigen. Beispielsweise kann über einen Vorschlag zum Upgrade eines Proxy-Contracts auf eine neue Implementierung von Token-Inhabern abgestimmt werden.
Dezentrale Governance kann vorteilhaft sein, insbesondere weil sie die Interessen von Entwicklern und Endbenutzern in Einklang bringt. Dennoch können Smart-Contract-Governance-Mechanismen neue Risiken mit sich bringen, wenn sie falsch implementiert werden. Ein plausibles Szenario ist, wenn ein Angreifer durch die Aufnahme eines Blitzkredits enorme Stimmrechte (gemessen an der Anzahl der gehaltenen Token) erwirbt und einen böswilligen Vorschlag durchsetzt.
Eine Möglichkeit, Probleme im Zusammenhang mit Onchain-Governance zu verhindern, ist die Verwendung eines Timelocks (opens in a new tab). Ein Timelock verhindert, dass ein Smart Contract bestimmte Aktionen ausführt, bis eine bestimmte Zeitspanne verstrichen ist. Andere Strategien umfassen die Zuweisung eines „Stimmgewichts“ zu jedem Token basierend darauf, wie lange er gesperrt war, oder die Messung der Stimmkraft einer Adresse zu einem historischen Zeitpunkt (z. B. 2-3 Blöcke in der Vergangenheit) anstelle des aktuellen Blocks. Beide Methoden verringern die Möglichkeit, schnell Stimmrechte anzuhäufen, um Onchain-Abstimmungen zu beeinflussen.
Mehr zum Entwerfen sicherer Governance-Systeme (opens in a new tab), zu verschiedenen Abstimmungsmechanismen in DAOs (opens in a new tab) und zu den häufigen DAO-Angriffsvektoren, die DeFi nutzen (opens in a new tab), in den geteilten Links.
8. Reduzieren Sie die Komplexität im Code auf ein Minimum
Traditionelle Softwareentwickler sind mit dem KISS-Prinzip („Keep it simple, stupid“) vertraut, das davon abrät, unnötige Komplexität in das Software-Design einzuführen. Dies folgt dem langjährigen Gedanken, dass „komplexe Systeme auf komplexe Weise scheitern“ und anfälliger für kostspielige Fehler sind.
Die Dinge einfach zu halten, ist beim Schreiben von Smart Contracts von besonderer Bedeutung, da Smart Contracts potenziell große Werte kontrollieren. Ein Tipp, um beim Schreiben von Smart Contracts Einfachheit zu erreichen, ist die Wiederverwendung bestehender Bibliotheken, wie z. B. OpenZeppelin Contracts (opens in a new tab), wo immer dies möglich ist. Da diese Bibliotheken von Entwicklern ausführlich geprüft und getestet wurden, verringert ihre Verwendung die Wahrscheinlichkeit, Fehler einzuführen, indem neue Funktionen von Grund auf neu geschrieben werden.
Ein weiterer häufiger Ratschlag ist, kleine Funktionen zu schreiben und Verträge modular zu halten, indem die Geschäftslogik auf mehrere Verträge aufgeteilt wird. Das Schreiben von einfacherem Code reduziert nicht nur die Angriffsfläche in einem Smart Contract, sondern erleichtert es auch, über die Korrektheit des Gesamtsystems nachzudenken und mögliche Designfehler frühzeitig zu erkennen.
9. Verteidigen Sie sich gegen häufige Smart-Contract-Schwachstellen
Wiedereintritt
Die EVM erlaubt keine Nebenläufigkeit (Concurrency), was bedeutet, dass zwei an einem Nachrichtenaufruf beteiligte Verträge nicht gleichzeitig ausgeführt werden können. Ein externer Aufruf pausiert die Ausführung und den Speicher des aufrufenden Vertrags, bis der Aufruf zurückkehrt, woraufhin die Ausführung normal fortgesetzt wird. Dieser Prozess kann formal als Übertragung des Kontrollflusses (opens in a new tab) an einen anderen Vertrag beschrieben werden.
Obwohl meist harmlos, kann die Übertragung des Kontrollflusses an nicht vertrauenswürdige Verträge Probleme verursachen, wie z. B. Wiedereintritt. Ein Wiedereintritts-Angriff tritt auf, wenn ein böswilliger Vertrag in einen anfälligen Vertrag zurückruft, bevor der ursprüngliche Funktionsaufruf abgeschlossen ist. Diese Art von Angriff lässt sich am besten an einem Beispiel erklären.
Betrachten Sie einen einfachen Smart Contract (‚Victim‘), der es jedem ermöglicht, Ether einzuzahlen und abzuheben:
// Dieser Vertrag ist verwundbar. Nicht in der Produktion verwenden
contract Victim {
mapping (address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw() external {
uint256 amount = balances[msg.sender];
(bool success, ) = msg.sender.call.value(amount)("");
require(success);
balances[msg.sender] = 0;
}
}
Dieser Vertrag stellt eine withdraw()-Funktion zur Verfügung, um Benutzern das Abheben von zuvor im Vertrag eingezahltem ETH zu ermöglichen. Bei der Verarbeitung einer Abhebung führt der Vertrag die folgenden Operationen durch:
- Überprüft das ETH-Guthaben des Benutzers
- Sendet Gelder an die aufrufende Adresse
- Setzt ihr Guthaben auf 0 zurück, um zusätzliche Abhebungen durch den Benutzer zu verhindern
Die Funktion withdraw() im Vertrag Victim folgt einem „Checks-Interactions-Effects“-Muster. Sie überprüft (checks), ob die für die Ausführung erforderlichen Bedingungen erfüllt sind (d. h. der Benutzer hat ein positives ETH-Guthaben), und führt die Interaktion (interaction) durch, indem sie ETH an die Adresse des Aufrufers sendet, bevor sie die Auswirkungen (effects) der Transaktion anwendet (d. h. das Guthaben des Benutzers reduziert).
Wenn withdraw() von einem Externally Owned Account (EOA) aufgerufen wird, wird die Funktion wie erwartet ausgeführt: msg.sender.call.value() sendet ETH an den Aufrufer. Wenn jedoch msg.sender ein Smart-Contract-Konto ist, das withdraw() aufruft, wird das Senden von Geldern mit msg.sender.call.value() auch den an dieser Adresse gespeicherten Code zur Ausführung auslösen.
Stellen Sie sich vor, dies ist der an der Vertragsadresse bereitgestellte Code:
contract Attacker {
function beginAttack() external payable {
Victim(victim_address).deposit.value(1 ether)();
Victim(victim_address).withdraw();
}
function() external payable {
if (gasleft() > 40000) {
Victim(victim_address).withdraw();
}
}
}
Dieser Vertrag ist darauf ausgelegt, drei Dinge zu tun:
- Eine Einzahlung von einem anderen Konto akzeptieren (wahrscheinlich das EOA des Angreifers)
- 1 ETH in den Victim-Vertrag einzahlen
- Die im Smart Contract gespeicherten 1 ETH abheben
Daran ist nichts falsch, außer dass Attacker eine weitere Funktion hat, die withdraw() in Victimerneut aufruft, wenn das vom eingehendenmsg.sender.call.valueübrig gebliebene Gas mehr als 40.000 beträgt. Dies gibtAttackerdie Möglichkeit, wieder inVictimeinzutreten und mehr Gelder abzuheben, _bevor_ der erste Aufruf vonwithdraw` abgeschlossen ist. Der Zyklus sieht so aus:
- Attacker's EOA calls `Attacker.beginAttack()` with 1 ETH
- `Attacker.beginAttack()` deposits 1 ETH into `Victim`
- `Attacker` calls `withdraw() in `Victim`
- `Victim` checks `Attacker`’s balance (1 ETH)
- `Victim` sends 1 ETH to `Attacker` (which triggers the default function)
- `Attacker` calls `Victim.withdraw()` again (note that `Victim` hasn’t reduced `Attacker`’s balance from the first withdrawal)
- `Victim` checks `Attacker`’s balance (which is still 1 ETH because it hasn’t applied the effects of the first call)
- `Victim` sends 1 ETH to `Attacker` (which triggers the default function and allows `Attacker` to reenter the `withdraw` function)
- The process repeats until `Attacker` runs out of gas, at which point `msg.sender.call.value` returns without triggering additional withdrawals
- `Victim` finally applies the results of the first transaction (and subsequent ones) to its state, so `Attacker`’s balance is set to 0
Zusammenfassend lässt sich sagen, dass, da das Guthaben des Aufrufers erst auf 0 gesetzt wird, wenn die Funktionsausführung abgeschlossen ist, nachfolgende Aufrufe erfolgreich sein werden und es dem Aufrufer ermöglichen, sein Guthaben mehrmals abzuheben. Diese Art von Angriff kann verwendet werden, um einen Smart Contract von seinen Geldern zu leeren, wie es beim DAO-Hack 2016 (opens in a new tab) geschah. Wiedereintritts-Angriffe sind auch heute noch ein kritisches Problem für Smart Contracts, wie öffentliche Auflistungen von Wiedereintritts-Exploits (opens in a new tab) zeigen.
Wie man Wiedereintritts-Angriffe verhindert
Ein Ansatz zum Umgang mit Wiedereintritt ist die Befolgung des Checks-Effects-Interactions-Musters (opens in a new tab). Dieses Muster ordnet die Ausführung von Funktionen so an, dass Code, der notwendige Überprüfungen durchführt, bevor er mit der Ausführung fortfährt, an erster Stelle steht, gefolgt von Code, der den Vertragszustand manipuliert, und Code, der mit anderen Verträgen oder EOAs interagiert, an letzter Stelle steht.
Das Checks-Effects-Interactions-Muster wird in einer überarbeiteten Version des unten gezeigten Victim-Vertrags verwendet:
contract NoLongerAVictim {
function withdraw() external {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0;
(bool success, ) = msg.sender.call.value(amount)("");
require(success);
}
}
Dieser Vertrag führt eine Überprüfung (check) des Benutzerguthabens durch, wendet die Auswirkungen (effects) der Funktion withdraw() an (indem das Benutzerguthaben auf 0 zurückgesetzt wird) und fährt fort, die Interaktion (interaction) durchzuführen (Senden von ETH an die Adresse des Benutzers). Dies stellt sicher, dass der Vertrag seinen Speicher vor dem externen Aufruf aktualisiert, wodurch die Wiedereintritts-Bedingung beseitigt wird, die den ersten Angriff ermöglichte. Der Vertrag Attacker könnte immer noch in NoLongerAVictim zurückrufen, aber da balances[msg.sender] auf 0 gesetzt wurde, werden zusätzliche Abhebungen einen Fehler auslösen.
Eine weitere Option ist die Verwendung einer gegenseitigen Ausschluss-Sperre (allgemein als „Mutex“ bezeichnet), die einen Teil des Vertragszustands sperrt, bis ein Funktionsaufruf abgeschlossen ist. Dies wird mithilfe einer booleschen Variablen implementiert, die vor der Ausführung der Funktion auf true gesetzt wird und nach Abschluss des Aufrufs auf false zurückgesetzt wird. Wie im folgenden Beispiel zu sehen ist, schützt die Verwendung eines Mutex eine Funktion vor rekursiven Aufrufen, während der ursprüngliche Aufruf noch verarbeitet wird, wodurch der Wiedereintritt effektiv gestoppt wird.
pragma solidity ^0.7.0;
contract MutexPattern {
bool locked = false;
mapping(address => uint256) public balances;
modifier noReentrancy() {
require(!locked, "Blocked from reentrancy.");
locked = true;
_;
locked = false;
}
// Diese Funktion ist durch einen Mutex geschützt, sodass Wiedereintrittsaufrufe aus `msg.sender.call` heraus `withdraw` nicht erneut aufrufen können.
// Die `return`-Anweisung ergibt `true`, wertet aber dennoch die `locked = false`-Anweisung im Modifier aus
function withdraw(uint _amount) public payable noReentrancy returns(bool) {
require(balances[msg.sender] >= _amount, "No balance to withdraw.");
balances[msg.sender] -= _amount;
(bool success, ) = msg.sender.call{value: _amount}("");
require(success);
return true;
}
}
Sie können auch ein Pull-Payments (opens in a new tab)-System verwenden, das von Benutzern verlangt, Gelder aus den Smart Contracts abzuheben, anstelle eines „Push-Payments“-Systems, das Gelder an Konten sendet. Dies beseitigt die Möglichkeit, versehentlich Code an unbekannten Adressen auszulösen (und kann auch bestimmte Denial-of-Service-Angriffe verhindern).
Integer-Unterläufe und -Überläufe
Ein Integer-Überlauf tritt auf, wenn die Ergebnisse einer arithmetischen Operation außerhalb des akzeptablen Wertebereichs liegen, was dazu führt, dass sie auf den niedrigsten darstellbaren Wert „überrollen“. Beispielsweise kann ein uint8 nur Werte bis zu 2^8-1=255 speichern. Arithmetische Operationen, die zu Werten über 255 führen, werden überlaufen und uint auf 0 zurücksetzen, ähnlich wie der Kilometerzähler eines Autos auf 0 zurückgesetzt wird, sobald er den maximalen Kilometerstand (999999) erreicht.
Integer-Unterläufe passieren aus ähnlichen Gründen: Die Ergebnisse einer arithmetischen Operation fallen unter den akzeptablen Bereich. Angenommen, Sie versuchen, 0 in einem uint8 zu dekrementieren, würde das Ergebnis einfach auf den maximal darstellbaren Wert (255) überrollen.
Sowohl Integer-Überläufe als auch -Unterläufe können zu unerwarteten Änderungen an den Zustandsvariablen eines Vertrags führen und eine ungeplante Ausführung zur Folge haben. Unten finden Sie ein Beispiel, das zeigt, wie ein Angreifer einen arithmetischen Überlauf in einem Smart Contract ausnutzen kann, um eine ungültige Operation durchzuführen:
pragma solidity ^0.7.6;
// Dieser Vertrag ist als Zeittresor konzipiert.
// Der Benutzer kann in diesen Vertrag einzahlen, aber mindestens eine Woche lang nicht abheben.
// Der Benutzer kann die Wartezeit auch über die 1-wöchige Wartezeit hinaus verlängern.
/*
1. TimeLock bereitstellen
2. Attack mit der Adresse von TimeLock bereitstellen
3. Attack.attack aufrufen und 1 Ether senden. Sie werden sofort in der Lage sein,
Ihren Ether abzuheben.
Was ist passiert?
Attack verursachte einen Überlauf von TimeLock.lockTime und konnte vor
Ablauf der 1-wöchigen Wartezeit abheben.
*/
contract TimeLock {
mapping(address => uint) public balances;
mapping(address => uint) public lockTime;
function deposit() external payable {
balances[msg.sender] += msg.value;
lockTime[msg.sender] = block.timestamp + 1 weeks;
}
function increaseLockTime(uint _secondsToIncrease) public {
lockTime[msg.sender] += _secondsToIncrease;
}
function withdraw() public {
require(balances[msg.sender] > 0, "Insufficient funds");
require(block.timestamp > lockTime[msg.sender], "Lock time not expired");
uint amount = balances[msg.sender];
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Failed to send Ether");
}
}
contract Attack {
TimeLock timeLock;
constructor(TimeLock _timeLock) {
timeLock = TimeLock(_timeLock);
}
fallback() external payable {}
function attack() public payable {
timeLock.deposit{value: msg.value}();
/*
wenn t = aktuelle Sperrzeit, dann müssen wir x finden, sodass
x + t = 2**256 = 0
also x = -t
2**256 = type(uint).max + 1
also x = type(uint).max + 1 - t
*/
timeLock.increaseLockTime(
type(uint).max + 1 - timeLock.lockTime(address(this))
);
timeLock.withdraw();
}
}
Wie man Integer-Unterläufe und -Überläufe verhindert
Ab Version 0.8.0 lehnt der Solidity-Compiler Code ab, der zu Integer-Unterläufen und -Überläufen führt. Verträge, die mit einer niedrigeren Compiler-Version kompiliert wurden, sollten jedoch entweder Überprüfungen bei Funktionen durchführen, die arithmetische Operationen beinhalten, oder eine Bibliothek (z. B. SafeMath (opens in a new tab)) verwenden, die auf Unterlauf/Überlauf prüft.
Orakel-Manipulation
Orakel beziehen offchain-Informationen und senden sie onchain, damit Smart Contracts sie nutzen können. Mit Orakeln können Sie Smart Contracts entwerfen, die mit offchain-Systemen wie Kapitalmärkten interagieren, was ihre Anwendungsmöglichkeiten erheblich erweitert.
Aber wenn das Orakel korrumpiert ist und falsche Informationen onchain sendet, werden Smart Contracts basierend auf fehlerhaften Eingaben ausgeführt, was Probleme verursachen kann. Dies ist die Grundlage des „Orakel-Problems“, das sich mit der Aufgabe befasst, sicherzustellen, dass Informationen von einem Blockchain-Orakel genau, aktuell und rechtzeitig sind.
Ein damit verbundenes Sicherheitsbedenken ist die Verwendung eines Onchain-Orakels, wie z. B. einer dezentralen Börse, um den Spotpreis für einen Vermögenswert zu erhalten. Kreditvergabe-Plattformen in der Branche für Dezentralisierte Finanzen (DeFi) tun dies häufig, um den Wert der Sicherheiten eines Benutzers zu bestimmen und festzulegen, wie viel er leihen kann.
DEX-Preise sind oft genau, was größtenteils Arbitrageuren zu verdanken ist, die die Parität auf den Märkten wiederherstellen. Sie sind jedoch anfällig für Manipulationen, insbesondere wenn das Onchain-Orakel die Vermögenspreise basierend auf historischen Handelsmustern berechnet (wie es normalerweise der Fall ist).
Beispielsweise könnte ein Angreifer den Spotpreis eines Vermögenswerts künstlich in die Höhe treiben, indem er einen Blitzkredit aufnimmt, kurz bevor er mit Ihrem Kreditvertrag interagiert. Die Abfrage des Vermögenspreises bei der DEX würde einen überdurchschnittlich hohen Wert zurückgeben (da die große „Kauforder“ des Angreifers die Nachfrage nach dem Vermögenswert verzerrt), was es ihm ermöglicht, mehr zu leihen, als er sollte. Solche „Blitzkredit-Angriffe“ wurden genutzt, um die Abhängigkeit von Preis-Orakeln bei DeFi-Anwendungen auszunutzen, was Protokolle Millionen an verlorenen Geldern kostete.
Wie man Orakel-Manipulation verhindert
Die Mindestanforderung zur Vermeidung von Orakel-Manipulation (opens in a new tab) ist die Verwendung eines dezentralen Orakel-Netzwerks, das Informationen aus mehreren Quellen abfragt, um Single Points of Failure zu vermeiden. In den meisten Fällen verfügen dezentrale Orakel über integrierte kryptoökonomische Anreize, um Orakel-Knoten zu ermutigen, korrekte Informationen zu melden, was sie sicherer macht als zentralisierte Orakel.
Wenn Sie planen, ein Onchain-Orakel für Vermögenspreise abzufragen, sollten Sie eines in Betracht ziehen, das einen zeitgewichteten Durchschnittspreis-Mechanismus (TWAP) implementiert. Ein TWAP-Orakel (opens in a new tab) fragt den Preis eines Vermögenswerts zu zwei verschiedenen Zeitpunkten ab (die Sie ändern können) und berechnet den Spotpreis basierend auf dem ermittelten Durchschnitt. Die Wahl längerer Zeiträume schützt Ihr Protokoll vor Preismanipulationen, da kürzlich ausgeführte große Aufträge die Vermögenspreise nicht beeinflussen können.
Ressourcen zur Smart-Contract-Sicherheit für Entwickler
Tools zur Analyse von Smart Contracts und zur Überprüfung der Code-Korrektheit
-
Test-Tools und Bibliotheken - Sammlung von branchenüblichen Tools und Bibliotheken zur Durchführung von Unit-Tests, statischer Analyse und dynamischer Analyse von Smart Contracts.
-
Tools für formale Verifikation - Tools zur Überprüfung der funktionalen Korrektheit in Smart Contracts und zur Prüfung von Invarianten.
-
Smart-Contract-Auditing-Dienste - Auflistung von Organisationen, die Smart-Contract-Auditing-Dienste für Ethereum-Entwicklungsprojekte anbieten.
-
Bug-Bounty-Plattformen - Plattformen zur Koordination von Bug Bounties und zur Belohnung der verantwortungsvollen Offenlegung kritischer Schwachstellen in Smart Contracts.
-
Fork Checker (opens in a new tab) - Ein kostenloses Online-Tool zur Überprüfung aller verfügbaren Informationen bezüglich eines geforkten Vertrags.
-
ABI Encoder (opens in a new tab) - Ein kostenloser Online-Dienst zur Codierung Ihrer Solidity-Vertragsfunktionen und Konstruktor-Argumente.
-
Aderyn (opens in a new tab) - Statischer Analysator für Solidity, der die abstrakten Syntaxbäume (AST) durchläuft, um vermutete Schwachstellen genau zu lokalisieren und Probleme in einem leicht verständlichen Markdown-Format auszugeben.
Tools zur Überwachung von Smart Contracts
- Tenderly Real-Time Alerting (opens in a new tab) - Ein Tool, um Echtzeit-Benachrichtigungen zu erhalten, wenn ungewöhnliche oder unerwartete Ereignisse bei Ihren Smart Contracts oder Wallets auftreten.
Tools zur sicheren Verwaltung von Smart Contracts
-
Safe (opens in a new tab) - Eine auf Ethereum laufende Smart-Contract-Wallet, die eine Mindestanzahl von Personen erfordert, um eine Transaktion zu genehmigen, bevor sie ausgeführt werden kann (M-von-N).
-
OpenZeppelin Contracts (opens in a new tab) - Vertragsbibliotheken zur Implementierung administrativer Funktionen, einschließlich Vertragsbesitz, Upgrades, Zugriffskontrollen, Governance, Pausierbarkeit und mehr.
Smart-Contract-Auditing-Dienste
-
ConsenSys Diligence (opens in a new tab) - Smart-Contract-Auditing-Dienst, der Projekten im gesamten Blockchain-Ökosystem hilft, sicherzustellen, dass ihre Protokolle bereit für den Start sind und zum Schutz der Benutzer entwickelt wurden.
-
CertiK (opens in a new tab) - Blockchain-Sicherheitsunternehmen, das Pionierarbeit beim Einsatz modernster Technologie zur formalen Verifikation bei Smart Contracts und Blockchain-Netzwerken leistet.
-
Trail of Bits (opens in a new tab) - Cybersicherheitsunternehmen, das Sicherheitsforschung mit einer Angreifermentalität kombiniert, um Risiken zu reduzieren und Code zu härten.
-
PeckShield (opens in a new tab) - Blockchain-Sicherheitsunternehmen, das Produkte und Dienstleistungen für die Sicherheit, Privatsphäre und Benutzerfreundlichkeit des gesamten Blockchain-Ökosystems anbietet.
-
QuantStamp (opens in a new tab) - Auditing-Dienst, der die breite Akzeptanz der Blockchain-Technologie durch Sicherheits- und Risikobewertungsdienste fördert.
-
OpenZeppelin (opens in a new tab) - Smart-Contract-Sicherheitsunternehmen, das Sicherheitsaudits für verteilte Systeme anbietet.
-
Runtime Verification (opens in a new tab) - Sicherheitsunternehmen, das sich auf die formale Modellierung und Verifikation von Smart Contracts spezialisiert hat.
-
Hacken (opens in a new tab) - Web3-Cybersicherheitsauditor, der einen 360-Grad-Ansatz für die Blockchain-Sicherheit bietet.
-
Nethermind (opens in a new tab) - Auditing-Dienste für Solidity und Cairo, die die Integrität von Smart Contracts und die Sicherheit der Benutzer auf Ethereum und Starknet gewährleisten.
-
HashEx (opens in a new tab) - HashEx konzentriert sich auf Blockchain- und Smart-Contract-Auditing, um die Sicherheit von Kryptowährungen zu gewährleisten, und bietet Dienstleistungen wie Smart-Contract-Entwicklung, Penetrationstests und Blockchain-Beratung an.
-
Code4rena (opens in a new tab) - Wettbewerbsorientierte Audit-Plattform, die Smart-Contract-Sicherheitsexperten Anreize bietet, Schwachstellen zu finden und dabei zu helfen, Web3 sicherer zu machen.
-
CodeHawks (opens in a new tab) - Wettbewerbsorientierte Audit-Plattform, die Smart-Contract-Auditing-Wettbewerbe für Sicherheitsforscher veranstaltet.
-
Cyfrin (opens in a new tab) - Web3-Sicherheits-Powerhouse, das Krypto-Sicherheit durch Produkte und Smart-Contract-Auditing-Dienste fördert.
-
ImmuneBytes (opens in a new tab) - Web3-Sicherheitsfirma, die Sicherheitsaudits für Blockchain-Systeme durch ein Team erfahrener Auditoren und erstklassige Tools anbietet.
-
Oxorio (opens in a new tab) - Smart-Contract-Audits und Blockchain-Sicherheitsdienste mit Expertise in EVM, Solidity, ZK und kettenübergreifender Technologie für Krypto-Firmen und Projekte im Bereich Dezentralisierte Finanzen (DeFi).
-
Inference (opens in a new tab) - Sicherheits-Auditing-Unternehmen, spezialisiert auf Smart-Contract-Auditing für EVM-basierte Blockchains. Dank seiner erfahrenen Auditoren identifizieren sie potenzielle Probleme und schlagen umsetzbare Lösungen vor, um diese vor der Bereitstellung zu beheben.
Bug-Bounty-Plattformen
-
Immunefi (opens in a new tab) - Bug-Bounty-Plattform für Smart Contracts und Dezentralisierte Finanzen (DeFi)-Projekte, auf der Sicherheitsforscher Code überprüfen, Schwachstellen offenlegen, bezahlt werden und Krypto sicherer machen.
-
HackerOne (opens in a new tab) - Plattform für Schwachstellenkoordination und Bug Bounties, die Unternehmen mit Penetrationstestern und Cybersicherheitsforschern verbindet.
-
HackenProof (opens in a new tab) - Experten-Bug-Bounty-Plattform für Krypto-Projekte (DeFi, Smart Contracts, Wallets, CEX und mehr), auf der Sicherheitsexperten Triage-Dienste anbieten und Forscher für relevante, verifizierte Fehlerberichte bezahlt werden.
-
Sherlock (opens in a new tab) - Underwriter im Web3 für Smart-Contract-Sicherheit, mit Auszahlungen für Auditoren, die über Smart Contracts verwaltet werden, um sicherzustellen, dass relevante Bugs fair bezahlt werden.
-
CodeHawks (opens in a new tab) - Wettbewerbsorientierte Bug-Bounty-Plattform, auf der Auditoren an Sicherheitswettbewerben und Herausforderungen sowie (bald) an ihren eigenen privaten Audits teilnehmen.
Publikationen bekannter Smart-Contract-Schwachstellen und -Exploits
-
ConsenSys: Bekannte Smart-Contract-Angriffe (opens in a new tab) - Anfängerfreundliche Erklärung der wichtigsten Vertrags-Schwachstellen, mit Beispielcode für die meisten Fälle.
-
SWC Registry (opens in a new tab) - Kuratierte Liste von Common Weakness Enumeration (CWE)-Einträgen, die für Ethereum-Smart-Contracts gelten.
-
Rekt (opens in a new tab) - Regelmäßig aktualisierte Publikation von aufsehenerregenden Krypto-Hacks und -Exploits, zusammen mit detaillierten Post-Mortem-Berichten.
Herausforderungen zum Erlernen der Smart-Contract-Sicherheit
-
Awesome BlockSec CTF (opens in a new tab) - Kuratierte Liste von Blockchain-Sicherheits-Wargames, Herausforderungen und Capture The Flag (opens in a new tab)-Wettbewerben sowie Lösungsberichten.
-
Damn Vulnerable DeFi (opens in a new tab) - Wargame zum Erlernen der offensiven Sicherheit von Smart Contracts im Bereich Dezentralisierte Finanzen (DeFi) und zum Aufbau von Fähigkeiten in der Fehlersuche und im Sicherheits-Auditing.
-
Ethernaut (opens in a new tab) - Web3/Solidity-basiertes Wargame, bei dem jedes Level ein Smart Contract ist, der „gehackt“ werden muss.
-
HackenProof x HackTheBox (opens in a new tab) - Smart-Contract-Hacking-Herausforderung, eingebettet in ein Fantasy-Abenteuer. Der erfolgreiche Abschluss der Herausforderung gewährt zudem Zugang zu einem privaten Bug-Bounty-Programm.
Best Practices zur Sicherung von Smart Contracts
-
ConsenSys: Best Practices für die Sicherheit von Ethereum-Smart-Contracts (opens in a new tab) - Umfassende Liste von Richtlinien zur Sicherung von Ethereum-Smart-Contracts.
-
Nascent: Simple Security Toolkit (opens in a new tab) - Sammlung praktischer, sicherheitsorientierter Leitfäden und Checklisten für die Smart-Contract-Entwicklung.
-
Solidity Patterns (opens in a new tab) - Nützliche Zusammenstellung sicherer Muster und Best Practices für die Smart-Contract-Programmiersprache Solidity.
-
Solidity-Dokumentation: Sicherheitsüberlegungen (opens in a new tab) - Richtlinien zum Schreiben sicherer Smart Contracts mit Solidity.
-
Smart Contract Security Verification Standard (opens in a new tab) - Vierzehnteilige Checkliste, die erstellt wurde, um die Sicherheit von Smart Contracts für Entwickler, Architekten, Sicherheitsprüfer und Anbieter zu standardisieren.
-
Smart-Contract-Sicherheit und Auditing lernen (opens in a new tab) - Ultimativer Kurs für Smart-Contract-Sicherheit und Auditing, entwickelt für Smart-Contract-Entwickler, die ihre Sicherheits-Best-Practices verbessern und Sicherheitsforscher werden möchten.