Verhindern von Broken Access Control Attacks in Solidity

Verfasst von

Gewährleistungsfehler bei Zugriffskontrollen treten auf, wenn ein Solidity-Vertrag einem unzuverlässigen Anrufer die Möglichkeit gibt, eine zustandsändernde Fähigkeit zu nutzen, die eigentlich eingeschränkt sein sollte, wie z.B. Vermögensbewegungen, Änderungen an der Implementierung, Rollenzuweisungen oder die Konfiguration eines vertrauenswürdigen Adresskontos. Der Angreifer muss keine Kryptografie brechen: Er nutzt eine fehlende, fehlerhafte oder zu breit gefasste Zugriffsprüfung aus, um effektive Privilegienerweiterungen zu erzielen.

Die Auswirkungen können protokollübergreifend sein, da privilegierte Funktionen oft Treuhandfonds oder governance-kritische Konfigurationen steuern. Poly Network verlor am 10.08.2021 611,0 Mio. USD auf Ethereum, BSC und Polygon in einem Vorfall, der laut DefiLlama als Unzureichende Zugriffskontrolle klassifiziert wurde. Zugriffsrechte sind daher kein UI-Thema oder eine administrative Feinheit. Sie sind Teil der Kern-Sicherheitsgrenze eines Vertrags.

Was ist eine Schwachstelle bei der Zugriffskontrolle in Solidity?

Eine Sicherheitslücke bei der Zugriffskontrolle besteht, wenn ein Vertrag nicht zuverlässig überprüft, ob msg.sender für eine privilegierte Aktion autorisiert ist, oder wenn das Autorisierungsmodell mehr Befugnisse gewährt, als für die Aktion notwendig sind. In Solidity zeigt sich dies meist bei extern aufrufbaren Funktionen, die sensible Speicherbereiche modifizieren, Vermögenswerte transferieren, Code upgraden oder vertrauenswürdige Gegenparteien ändern.

Ein Vertrag kann auch dann anfällig sein, wenn eine owner-Variabel existiert. Entscheidend ist jedoch, ob jeder einzelne Pfad für privilegierte Ausführungen korrekt überprüft, wer die Berechtigung besitzt — inklusive Hilfsfunktionen, Initialisierer, Rollenmanagement-Funktionen und Upgrade-Hooks.

Eine typische Angriffskette bei unzureichender Zugriffskontrolle folgt diesem Ablauf:

  1. Der Angreifer identifiziert eine extern aufrufbare Funktion mit privilegierten Konsequenzen.
  2. Die Funktion führt keine Überprüfung des Anrufers durch, prüft die falsche Adresse oder vertraut auf vom Angreifer kontrollierten Zustand.
  3. Der Angreifer ruft die Funktion direkt auf, um Frontend-Beschränkungen zu umgehen.
  4. Der Aufruf gewährt eine Rolle, ändert eine vertrauenswürdige Adresse oder initiiert eine Vermögensbewegung.
  5. Der Angreifer nutzt die dadurch gewonnenen Rechte, um Gelder zu extrahieren oder das Protokollverhalten zu verändern.
  6. Der Vertrag akzeptiert die Transaktion, weil die EVM nur On-Chain-Checks durchführt.

Frontend-Buttons, Dokumentationen oder der vorgesehenen Betriebsvorgaben schränken direkte Vertragsaufrufe nicht ein. Jeder Account kann calldata an eine öffentliche oder externe Funktion schicken. Solidity-Code muss daher die Zugriffsrichtlinien exakt an der Stelle durchsetzen, an der eine sensible Zustandsänderung erfolgt.

Welche Solidity-Muster führen zu Angriffen auf die Zugriffskontrolle und Privilegienerweiterungen?

Fehlerhafte Zugriffskontroll-Implementierungen entstehen häufig, wenn Entwickler Konfigurations-Setter, Verwaltungs-Hilfsfunktionen oder Initialisierungswege offenlegen, ohne die Tatsache zu berücksichtigen, dass jede öffentliche Funktion eine API für Angreifer darstellt. Das gefährliche Muster ist nicht nur das Fehlen eines onlyOwner-Modifiers; es umfasst auch Zugriffsrechte, die veränderbar durch beliebige Anrufer sind, falsch vererbte Rechte, inkonsistent angewendete Zugriffsprüfung oder Rechte, die zu breit für die jeweilige Operation sind.

Häufige Fehler sind:

  • Öffentliche Setter, die jedem erlauben, eine Treasury, Oracle, Implementierung, Operator oder Begünstigten zu ersetzen.
  • Rollenmanagement-Funktionen ohne einen Administrator-Check.
  • Initialisierer, die nach Deployment aufgerufen werden können oder von unbefugten Konten.
  • Funktionen, die tx.origin prüfen anstatt msg.sender.
  • Eine privilegierte interne Funktion, die durch einen ungeschützten externen Wrapper aufgerufen werden kann.
  • Eine einzige Administratorrolle, die alle Operationen ausführen kann, was den Schadensradius erhöht.
  • Autorisierung basierend auf einer vom Nutzer bereitgestellten Adresse anstatt auf eine unveränderliche oder kontrollierte Rollenzuordnung.
  • Upgrade-Funktionen, die den Aufrufer validieren, aber nicht die neue Implementierung oder den Upgrade-Pfad.

Dieses Muster ist besonders subtil:

function setOperator(address newOperator) external {
    operator = newOperator;
}

Die Zahlungsfunktion erfordert vielleicht korrekt msg.sender == operator, aber die Zugriffskontrollgrenze ist bereits durchbrochen, weil jeder sich selbst zum Operator ernennen kann. Entwickler sollten alle sensiblen Funktionen rückverfolgen, um zu prüfen, wer die erforderliche Rolle erwerben kann.

Soken sieht die Rollenzuweisung und die Konfiguration vertrauenswürdiger Adressen als eigenständige privilegierte Operationen. Ein sicheres Zugriffsdesign schützt sowohl die endgültige Vermögensübertragung als auch jede Route, um sie freizuschalten.

Wie sieht eine Schwachstelle bei Zugriffskontrolle in Solidity-Code aus?

Dieses verwundbare Vault prüft den Anrufer vor Auszahlung, aber die Funktion setPayoutOperator ist öffentlich. Ein Angreifer kann sich selbst als Operator zuweisen und anschließend pay aufrufen, wodurch die nachfolgende Autorisierungsüberprüfung ihre Bedeutung verliert.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract VulnerablePayoutVault {
    address public payoutOperator;

    constructor(address initialOperator) {
        payoutOperator = initialOperator;
    }

    receive() external payable {}

    function setPayoutOperator(address newOperator) external {
        // ANFÄLLIG: Jeder kann sich selbst Auszahlungsrecht gewähren.
        payoutOperator = newOperator;
    }

    function pay(address payable recipient, uint256 amount) external {
        require(msg.sender == payoutOperator, "nicht operator");
        require(address(this).balance >= amount, "nicht genug Guthaben");

        (bool sent, ) = recipient.call{value: amount}("");
        require(sent, "Zahlung fehlgeschlagen");
    }
}

Die Lösung trennt Verwaltung von Operationen. Nur der Eigentümer kann die Rolle für Auszahlungen beschränken oder aufheben, während ein Auszahlungsmann nicht Rollen verwalten oder Eigentum ändern kann.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract FixedPayoutVault {
    address public owner;
    mapping(address => bool) public payoutOperators;

    modifier onlyOwner() {
        require(msg.sender == owner, "nicht Eigentümer");
        _;
    }

    modifier onlyPayoutOperator() {
        require(payoutOperators[msg.sender], "nicht payout-Operator");
        _;
    }

    constructor(address initialOwner, address initialOperator) {
        require(initialOwner != address(0), "Nulladresse Eigentümer");
        require(initialOperator != address(0), "Nulladresse Operator");
        owner = initialOwner;
        payoutOperators[initialOperator] = true;
    }

    receive() external payable {}

    function setPayoutOperator(address operator, bool allowed) external onlyOwner {
        require(operator != address(0), "Nulladresse");
        // FIX: Nur der Eigentümer kann privilegierte Rollen ändern.
        payoutOperators[operator] = allowed;
    }

    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "Nulladresse");
        owner = newOwner;
    }

    function pay(address payable recipient, uint256 amount)
        external
        onlyPayoutOperator
    {
        require(address(this).balance >= amount, "nicht genug Guthaben");
        (bool sent, ) = recipient.call{value: amount}("");
        require(sent, "Zahlung fehlgeschlagen");
    }
}

Wenn Rollenänderungen, Upgrade-Berechtigungen oder Abhebungen vom Treasury in deinem System vorhanden sind, sollte eine Smart-Contract-Sicherheitsüberprüfung mit Fokus auf Zugriffskontrolle nachvollziehen, ob alle Wege zu diesen Fähigkeiten richtig eingeschränkt sind.

Wie können Solidity-Entwickler unzureichende Zugriffskontroll-Schwachstellen verhindern?

Vermeidung von Fehlern bei Zugriffskontrollen erfordert ein explizites Berechtigungsmodell, nicht nur verstreute require-Prüfungen nach der Implementierung. Es ist notwendig, genau festzulegen, welcher Akteur welche sensiblen Operationen ausführen darf, warum diese Befugnisse bestehen und welche kleineren Rollen Routineaufgaben sicher erledigen können.

Technik Was sie verhindert Gas- oder Komplexitätskosten Einschränkungen
onlyOwner-Modifier Unbefugte Verwaltung von Owner-only-Funktionen Ein Speicherzugriff pro geschütztem Call Ein kompromittierter Eigentümer besitzt weiterhin volle Eigentümerrechte
Rollenzuordnungen oder OpenZeppelin AccessControl Unbefugte Nutzung separater Betriebsrollen Speicherzugriffe und Rollenmanagement-Logik Schlechte Rollengestaltung kann zu übermäßigen Privilegien führen
Least-privilege-Rollen Ein Betreiber oder Operator nutzt unzugehörige admin-Rechte Mehr Funktionen und Rollendefinitionen pflegen Klare Betriebsgrenzen erforderlich
Timelocks für kritische Änderungen Sofortige bösartige Upgrades oder Parameteränderungen Verzögerte Ausführung und zusätzliche Verträge Keine Verhinderung bösartiger Aktionen nach der Verzögerung, außer Nutzer können reagieren
Multisignatur-verwaltung Ein einzelner Schlüssel ändert privilegierten Status unilateral Koordination der Signaturen und Betriebsaufwand Gemeinsame Signaturen oder schwache Policies bleiben riskant
Einmalige Initialisierungsprüfungen Unbefugte oder wiederholte Initialisierung Ein Speicher-Flag und Initialisierungs-Logik Deployment-Verfahren müssen weiterhin die gewünschte Autorität setzen

Nutze gut geprüfte Ownership- und Rollen-Bibliotheken, aber behandle diese nicht als vollständiges Sicherheitsmodell. Beispiel: OpenZeppelin Ownable schafft Eigentümermechanismen, die Protokoll-Teams müssen aber weiterhin entscheiden, ob Eigentum Kontrolle über Pausen, Upgrades, Gebühren, Oracle-Austausch oder Notfallwiederherstellung übernehmen soll.

Vermeide tx.origin bei der Autorisierung. Es lässt sich durch Zwischenverträge beeinflussen und identifiziert nicht den unmittelbaren Anrufer. Nutze msg.sender und überprüfe diesen anhand einer festgelegten Eigentümer-, Rollen-, Multi-Sig- oder vertragspezifischen Autorisierungsregel.

Welche echten Vorfälle verdeutlichen die Folgen von Zugriffskontrollangriffen?

Laut DefiLlama wurden zwischen 2020 und 2026 130 Sicherheitsvorfälle bei Smart Contracts registriert, die als Unzureichende Zugriffskontrolle klassifiziert sind, ohne Börsen- oder Wallet-Hacks, mit Gesamtschäden von 909,7 Mio. USD. Die folgenden bestätigten Fälle zeigen, dass Mängel bei der Zugriffskontrolle Brücken, DeFi-Protokolle, Bots und Anwendungen auf mehreren Chains treffen können.

Protokoll Datum Betrag Chain
Poly Network 2021-08-10 611,0 Mio. USD Ethereum, BSC, Polygon
Mirror 2021-10-08 90,0 Mio. USD Terra
Wintermute 2022-06-05 17,6 Mio. USD Optimism
ValueDefi 2021-05-05 10,0 Mio. USD BSC
Cork V1 2025-05-28 12,0 Mio. USD Ethereum
SUPERFORTUNE AI 2026-05-27 15,2 Mio. USD Ethereum
The Sandbox 2026-08-22 675K USD Base, BSC, Ethereum
Radix 2026-08-31 1,2 Mio. USD Radix

Diese Vorfälle liefern eine klare Sicherheitslehre: Der wirtschaftliche Wert eines Protokolls ist gefährdet, wenn die Autoritätsgrenze eines Vertrags nicht dem beabsichtigten Vertrauensmodell entspricht. Die konkrete betroffene Funktion kann variieren, aber die Fehlerklasse bleibt gleich: Ein Akteur erlangt oder übt Befugnisse aus, die eigentlich vom Design her vorenthalten werden sollten.

Wie erkennt man Schwachstellen bei Zugriffskontrolle vor dem Deployment?

Die Erkennung von Zugriffskontrollfehlern erfordert die Zuordnung sensibler Zustandsänderungen zu ihren Autorisationsbedingungen und den Nachweis, dass keine alternative Aufrufroute diese Bedingungen umgehen kann. Automatisierte Tools helfen, verdächtige Muster zu identifizieren, aber menschliche Reviews sind essenziell, um Business-Authority, Vertrauensannahmen und Privilegienketten zu verstehen.

Nutze dazu diese Checkliste:

  1. Liste alle Funktionen auf, die Vermögenswerte transferieren, Rollen ändern, Code upgraden, Aktivitäten pausieren oder vertrauenswürdige Adressen ändern.
  2. Bestimme den vorgesehenen Anrufer und die Autorisierungsregel für jede Funktion.
  3. Verfolge jede Funktion, die diese Autorität gewähren, widerrufen, übertragen oder initialisieren kann.
  4. Überprüfe alle externen Wrappers, die zu privilegierten internen Funktionen führen.
  5. Stelle sicher, dass Initialisierungen nur einmal und nur unter dem vorgesehenen Deployment durchgeführt werden.
  6. Überprüfe, ob Notfallrollen keine routine- oder Governance-Aktivitäten mit ungeeigneter Berechtigung ausführen können.
  7. Teste Rollenwiderruf, Eigentümer-Transfer und Null-Adressen-Handling.
  8. Analysiere Proxies, vererbte Verträge und delegatecall-Wege im Rahmen derselben Autoritätsgrenze.

Slither kann fehlende Autorisierungen, gefährlichen tx.origin-Einsatz und inkonsistente Modifier kennzeichnen, aber die Ergebnisse sind manuell zu validieren. Foundry-Fuzzing ist hilfreich, um Aufrufe von beliebigen Adressen zu generieren und sicherzustellen, dass unautorisierte Anrufer keine privilegierten Zustände ändern können.

Invariant-Tests sind besonders effektiv. Beispielsweise kann eine Vault-Invariante festlegen, dass eine Adresse ohne Rollen für Auszahlungen niemals den Kontostand durch pay verringern darf. Eine weitere Invariante stellt sicher, dass nur der Eigentümer Rollenmitgliedschaften ändern kann. Diese Eigenschaften testen die Sicherheitsregeln direkt, anstatt nur erwartete Nutzerflüsse.

Sicherheits-Insight, Soken-Methodik: Betrachte Autorisierung als Capabilty-Graph, nicht nur als eine Liste von Modifiers. Jede privilegierte Handlung muss einen absichtlich geplanten und auditierbaren Pfad zur Autorität haben, und jeder unbeabsichtigte Pfad ist potenziell eine Eskalationsroute.

Schwachstellen bei Zugriffskontrolle werden vermieden, indem die Autorität explizit gemacht, jeder Rolle nur die minimal notwendigen Befugnisse zugewiesen und Funktionen, die diese Befugnisse verwalten, so sorgfältig wie Funktionen zum Vermögenstransfer geschützt werden. Eine korrekt eingeschränkte Abhebefunktion ist nicht sicher, wenn jeder den Abzuhandelner ernennen kann.

Beginne mit der Erstellung einer Autoritätskarte für deine deployten und geplanten Verträge, inklusive Proxies und Betriebs-Accounts. Wandelt jede Regel in einen Modifier und einen invarianten Test um. Für tiefergehende Solidity-Sicherheitsforschung und angrenzende Schwachstellenklassen besuche das Soken Hub.

Verfasst von

Häufig gestellte Fragen

Was ist eine broken access control Schwachstelle in Solidity?

Eine broken access control Schwachstelle in Solidity tritt auf, wenn ein Vertrag nicht zuverlässig bestätigt, dass msg.sender für eine privilegierte Aktion autorisiert ist. Das ermöglicht untrusted callern, Zustandsänderungen durchzuführen und Privilegien zu eskalieren.

Wie führen broken access control Angriffe zur Privilegieneskalation?

Solche Angriffe entstehen, wenn ein Solidity-Vertrag einem untrusted caller Zugriff auf eine für Autorisierte reservierte Fähigkeit gewährt, z.B. Assets bewegen oder Rollen zuweisen, was zu Privilegieneskalation führt.

Welche Solidity-Aktionen sollten durch Access Control eingeschränkt werden?

Jede zustandsverändernde Fähigkeit, die nicht für beliebige Aufrufer bestimmt ist, sollte durch Access Control geschützt werden, z.B. Assets bewegen oder Rollen zuweisen, um Sicherheitsrisiken zu minimieren.

Was passierte beim Poly Network Vorfall?

Poly Network verlor am 10.08.2021 611 Mio. USD in Ethereum, BSC und Polygon durch einen Zugriffskontrollfehler. Das zeigt, wie wichtig sichere Autorisierungsprüfungen sind, um Funds und Governance-Elemente zu schützen.

Warum ist Authorization eine zentrale Sicherheitsgrenze in Solidity?

Weil privilegierte Funktionen Kontrolle über Funds und kritische Governance-Einstellungen haben. Fehlende oder falsche Autorisierung kann untrusted callern Zugriff auf sensible Fähigkeiten geben, was eine Schwachstelle für das gesamte Protokoll darstellt.

Chat