Fehlende Eingabevalidierungsangriffe treten auf, wenn ein Solidity-Vertrag benutzerkontrollierte Adressen, Beträge, Identifikatoren, Preise oder Konfigurationswerte akzeptiert, ohne nachzuweisen, dass sie den wirtschaftlichen und sicherheitstechnischen Annahmen des Vertrags entsprechen. Um sie zu verhindern, validieren Sie jede externe Eingabe an der Vertrauensgrenze mit Allowlists, Grenzen, Zero-Address-Checks, Autorisierungen und Zustandsinvarianten, bevor Vermögenswerte verschoben oder Buchhaltungsänderungen vorgenommen werden.
Der Einfluss ist konkret: Qubit verlor am 28.01.2022 auf BSC 80,0 Mio. USD in einem Vorfall, der als Fehlende Eingabevalidierung eingestuft wurde. Diese Fehler sind nicht nur fehlerhafte Transaktionsprobleme. Ein nicht überprüfter Wert kann gültigen Solidity-Code dazu verleiten, eine ungültige geschäftliche Aktion auszuführen, wie z.B. die Gutschrift von nicht existierendem Sicherheiten, die Überweisung von Vermögenswerten an einen unehrlichen Empfänger oder die Schaffung von Schulden jenseits eines tatsächlichen Limits eines Kreditnehmers.
Was ist eine Sicherheitslücke bei der Eingabevalidierung in Solidity, und wie funktioniert ein Angriff?
Eine Sicherheitslücke bei der Eingabevalidierung in Solidity besteht, wenn ein Vertrag einen vom Anrufer bereitgestellten Wert als vertrauenswürdig behandelt, obwohl dieser Wert Berechtigungen, Asset-Buchhaltung, Preisgestaltung oder Zustandsübergänge kontrolliert. Ein Angreifer liefert einen Wert, der syntaktisch für die ABI gültig ist, wirtschaftlich jedoch ungültig für das Protocol, und nutzt den resultierenden Zustand, um Vermögenswerte abzuheben, Ansprüche zu minten oder Beschränkungen zu umgehen.
Solidity erzwingt Typen, nicht die Absicht des Protocols. Ein uint256 kann jede nicht-revertierende Zahl sein, und eine address kann eine EOA, ein bösartiger Vertrag, die Zero-Address oder ein nicht unterstütztes Token identifizieren. Der Vertrag muss die fehlenden semantischen Regeln durchsetzen.
Eine typische Angriffskette ist:
- Der Angreifer identifiziert eine öffentliche Funktion, die eine nicht überprüfte Menge, ein Token, einen Empfänger, einen Preis oder eine Kennung akzeptiert.
- Der Angreifer wählt einen Wert, der gegen die beabsichtigte Annahme des Protokolls verstößt.
- Der Vertrag zeichnet einen unsicheren Saldo, Anspruch, Schuldenlimit oder Autorisierungszustand auf.
- Der Angreifer ruft eine spätere Funktion auf, die dem vergifteten Zustand vertraut.
- Das Protokoll überweist Vermögenswerte oder mintet eine übertragenbare Forderung basierend auf diesem falschen Zustand.
- Andere Nutzer tragen den Verlust, wenn die Buchhaltungslücke sichtbar wird.
Die entscheidende Prüfungsfrage lautet: Welcher Tatsache behauptet diese Eingabe, darzustellen, und wo überprüft der Vertrag diese Tatsache unabhängig? Wenn die Antwort lautet „der Anrufer hat sie bereitgestellt“, liegt eine unangemessene Eingabevalidierungs-Sicherheitslücke vor.
Welche Solidity-Muster verursachen Eingabevalidierungsangriffe?
Eingabevalidierungsangriffe entstehen meist dort, wo ein Vertrag Flexibilität für Integrationen oder Nutzererfahrung akzeptiert, diese Flexibilität aber nicht auf den unterstützten Bereich des Protocols einschränkt. Das gefährliche Parameter ist oft nicht offensichtlich price oder amount; es kann eine Tokenadresse, Route, Empfänger, Tranche-ID, Beweis oder externe Vertragsadresse sein.
Häufige unsichere Muster sind:
- Vom Anrufer deklarierter Sicherheitenwert: Ein Kreditnehmer gibt den Wert an, der für die Berechnung der Kreditfähigkeit verwendet wird.
- Beliebige Token-Adressen: Eine Einzahlungsfunktion akzeptiert beliebige ERC-20-Token, inklusive solcher mit atypischem Transferverhalten.
- Nicht überprüfte Empfängeradressen: Eine Funktion akzeptiert
address(0), die Vertragsadresse selbst oder eine Adresse, die Custody-Regeln verletzt. - Unbegrenzte Prozentsätze und Verhältnisse: Eine Gebühr, LTV, Rabatt, Slippage oder Belohnungsrate überschreitet den vorgesehenen Basispunktbereich.
- Nicht validierte Array-Beziehungen: Parallele Arrays haben unterschiedliche Längen, doppelte Einträge werden akzeptiert, oder eine Route wiederholt ein Asset unerwartet.
- Zustandsübergänge ohne Vorbedingungen: Eine Anspruchs-, Stornierungs-, Einlösungs- oder Migrationsfunktion läuft im falschen Lebenszykluszustand.
- Externe Daten werden als Tatsache akzeptiert: Eine Funktion vertraut auf vom Anrufer bereitgestellte Preise, Saldi, Signaturen oder Rückgabewerte ohne Validierung.
Validierung muss kontextbezogen erfolgen. require(amount > 0) ist nützlich, beweist aber nicht, dass amount erschwinglich, gedeckt oder innerhalb einer Obergrenze liegt oder mit dem aktuellen Zustand übereinstimmt. Ebenso beweist die Überprüfung, dass eine Tokenadresse ungleich null ist, nicht, dass das Token genehmigt ist, erwartungsgemäß funktioniert oder zur richtigen Market gehört.
Die Review-Methodik von Soken behandelt jeden externen Parameter als einen versuchten Zustandsübergang: identifizieren Sie die Invariante, die dieser beeinflussen kann, und überprüfen Sie, dass die Funktion diese Invariante durchsetzt, bevor Daten geschrieben werden.
Wie sieht ein Beispiel für einen Eingabevalidierungsangriff in Solidity aus?
Dieses Beispiel für einen Eingabevalidierungsangriff ermöglicht es einem Kreditnehmer, seinen eigenen collateralValue einzureichen. Der Vertrag prüft, dass das beantragte Darlehen nicht größer ist als dieser Wert, aber er stellt nie sicher, dass der Kreditnehmer Sicherheiten in Höhe dieses Betrags eingezahlt hat. Ein Anrufer kann also beide Werte auf ein beliebiges Level setzen und sich die vom Kreditgeber bereitgestellten Vermögenswerte auszahlen lassen.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
}
contract UnsafeLender {
IERC20 public immutable asset;
mapping(address => uint256) public debt;
constructor(IERC20 asset_) {
require(address(asset_) != address(0), "zero asset");
asset = asset_;
}
function borrow(
uint256 collateralValue,
uint256 amount
) external {
require(collateralValue > 0, "no collateral");
require(amount <= collateralValue, "insufficient collateral");
// ANGRIFFSPUNKT: Kreditnehmer liefert Wert, der die Kreditlinie stützt.
debt[msg.sender] += amount;
require(asset.transfer(msg.sender, amount), "transfer failed");
}
}
Das sichere Design leitet die Kreditfähigkeit aus der tatsächlich erhaltenen Sicherheit ab. Die unveränderliche Asset-Adresse wirkt als enge Allowlist, die Konstruktorprüfung lehnt Null-Adressen ab, der LTV ist begrenzt, und die Balance-Delta-Prüfung validiert das Übertragungs-Invarianten, anstatt sich auf den angeforderten Einzahlungsbetrag zu verlassen.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
contract ValidatedLender {
IERC20 public immutable loanAsset;
IERC20 public immutable collateralAsset;
uint256 public immutable maxLtvBps;
mapping(address => uint256) public collateral;
mapping(address => uint256) public debt;
constructor(IERC20 loanAsset_, IERC20 collateralAsset_, uint256 maxLtvBps_) {
require(address(loanAsset_) != address(0), "zero loan asset");
require(address(collateralAsset_) != address(0), "zero collateral asset");
require(maxLtvBps_ > 0 && maxLtvBps_ <= 10_000, "invalid LTV");
loanAsset = loanAsset_;
collateralAsset = collateralAsset_;
maxLtvBps = maxLtvBps_;
}
function depositCollateral(uint256 amount) external {
require(amount > 0, "zero amount");
uint256 beforeBalance = collateralAsset.balanceOf(address(this));
require(collateralAsset.transferFrom(msg.sender, address(this), amount), "transfer failed");
uint256 received = collateralAsset.balanceOf(address(this)) - beforeBalance;
// FIX: Nur auf die tatsächlich empfangene Sicherheit reagieren.
require(received == amount, "unsupported token behavior");
collateral[msg.sender] += received;
}
function borrow(uint256 amount) external {
require(amount > 0, "zero amount");
uint256 limit = (collateral[msg.sender] * maxLtvBps) / 10_000;
require(debt[msg.sender] + amount <= limit, "borrow limit exceeded");
debt[msg.sender] += amount;
require(loanAsset.transfer(msg.sender, amount), "transfer failed");
}
}
Wenn Ihr Protokoll flexible Vermögenswerte, Routen oder Buchhaltungseingaben akzeptiert, sollten Sie eine adversarische Smart-Contract-Prüfung und Penetrationstest-Engagement durchführen, um nachzuvollziehen, ob jeder behauptete Wert vor Auswirkungen auf die Gelder unabhängig verifiziert wird.
Wie verhindern Sie Eingabevalidierungsangriffe in Solidity?
Das Verhindern von Eingabevalidierungsangriffen erfordert, Eingaben beim Eintritt zu validieren und die daraus resultierenden Annahmen durch explizite Invaranten während des gesamten Lebenszyklus des Vertrags aufrechtzuerhalten. Die beste Verteidigung ist kein Einzelne-Modifikator. Es ist eine Gestaltung, bei der jede sinnvolle Zustandsänderung klar definierte erlaubte Eingaben und eine überprüfbare Bedingung hat, die danach weiterhin gilt.
| Technik | Was sie verhindert | Gas- oder Komplexitätskosten | Einschränkung |
|---|---|---|---|
| Token- und Implementierungs-Allowlists | Nicht unterstützte ERC-20s, bösartige Adapter, beliebige externe Aufrufe | Speicher-Lookup oder unveränderliche Adressvergleiche | Genehmigte Token können dennoch wirtschaftliches Risiko darstellen |
| Grenzwert-Checks | Null-Beträge, zu hohe Raten, ungültige Basis-Punkte, unsichere Fristen | Gering, meist einige Vergleiche | Grenzen allein beweisen keine wirtschaftliche Korrektheit |
| Zero-Address- und Empfängerprüfungen | Asset-Burns, unbrauchbarer Besitz, ungültige Custody-Ziele | Gering, ein Adressvergleich | Eine Nicht-Null-Adresse kann trotzdem unzuverlässig sein |
| Autorisierungs- und Lebenszyklusprüfungen | Aufrufe im falschen Zustand oder durch falsche Akteure | Speicher-Lesen und Rollen-Design | Rollen benötigen sichere Verwaltung |
| Saldo-Delta-Validierung | Falsche Einzahlungs-Credits und nicht unterstütztes Token-Verhalten | Zusätzliche Token-Balance-Lesungen | Erfordert sorgfältiges Handling bei Rebasings Vermögenswerten |
| Invariante Validierung | Gebrochene Solvabilität, Versorgung, Schulden und Reserve-Beziehungen | Zusätzliche Lese- und Rechenoperationen | Invariante müssen das vollständige wirtschaftliche Modell abdecken |
Für konfigurierbare Protokolle validieren Sie die Konfiguration sowohl bei der Erstellung als auch bei der Nutzung. Ein Parameter, der durch Governance gesetzt wird, kann bei der Erstellung sicher sein, aber nach einer Änderung der Abhängigkeit unsicher werden. Für upgradefähige Systeme validieren Sie Initialisierer-Parameter mit der gleichen Strenge wie öffentliche Funktionen.
Sicherheits-Einblick: Die Soken-Methodik beginnt bei der Invariante, nicht bei der
require-Anweisung. Wenn Prüfer nicht angeben können, was nach einer nutzerkontrollierten Eingabe immer wahr bleiben muss, können sie auch nicht beurteilen, ob die Validierung ausreichend ist.
Welche echten Vorfälle wurden als Fehlende Eingabevalidierung klassifiziert?
Fehlende Eingabevalidierung wurde mit signifikanten Verlusten bei Smart Contracts im Bereich Kreditvergabe, Tausch und Asset-Management verbunden. Die Vorfallkategorie umfasst verschiedene Chains und Protokoll-Designs, was zeigt, dass unsachgemäße Eingabevalidierung eher ein Fehler der Protokoll-Logik ist als ein chainspezifischer Solidity-Fehler.
| Protokoll | Datum | Verlustbetrag | Chain |
|---|---|---|---|
| Qubit | 2022-01-28 | 80,0 Mio. USD | BSC |
| Hedgey | 2024-04-19 | 44,7 Mio. USD | Arbitrum, Ethereum |
| Transit Swap | 2022-10-02 | 28,9 Mio. USD | Ethereum, BSC |
| Pickle | 2020-11-22 | 19,7 Mio. USD | Ethereum |
Diese Vorfälle haben eine zentrale Lehre: Verträge können den Protokoll-Wahrheitsgehalt nicht sicher nur durch einen Wert ableiten, weil eine Transaktion diesen Wert erfolgreich kodiert und durchgeleitet hat. Asset-Systeme benötigen semantische Validierung um die spezifische Eigenschaft, die den Wert schützt — sei es erhaltene Sicherheit, ein unterstütztes Asset, eine autorisierte Route oder eine gültige Zustandsübergangsart.
Der DeFi-Llama klassifiziert 52 Smart-Contract-Vorfälle von 2020 bis 2026 unter „Fehlende Eingabevalidierung“ mit Gesamtschäden von 330,5 Mio. USD. Diese Bandbreite zeigt, warum Soken die Validierungsprüfung als eine ökonomische Sicherheitsmaßnahme ansieht, nicht nur als Checkliste oberflächlicher require-Statements.
Wie erkennen Sie unsachgemäße Eingabevalidierungs-Sicherheitslücken?
Sie erkennen Sicherheitslücken bei der Eingabevalidierung, indem Sie jeden extern erreichbaren Parameter bis zu den Schreibzugriffen, externen Aufrufen und Asset-Transfers nachvollziehen, die davon beeinflusst werden. Anschließend testen Sie, ob ungültige, aber ABI- gültige Werte eine Invariante verletzen können. Statische Analyse entdeckt manche fehlende Checks, doch szenarienbasierte Tests sind notwendig, um spezifische Annahmen des Protokolls zu überprüfen.
Nutzen Sie diese Prüfliste:
- Alle
external- undpublic-Parameter auflisten, die Wert, Berechtigung oder Routing beeinflussen. - Prüfen, ob jede Adresse ungleich null, genehmigt und für die Rolle geeignet ist.
- Jedes Asset gegen Protokoll-Obergrenzen, Salden, Schuldenlimits, Versorgungslimits und Dezimalannahmen überprüfen.
- Sicherstellen, dass Preise, Sicherheitenwerte und Salden von vertrauenswürdigen oder unabhängig verifizierten Quellen stammen.
- Array-Längen, Eindeutigkeit, Reihenfolge und Kreuz-Array-Indexbeziehungen validieren.
- Sicherstellen, dass jede Funktion nur erlaubte Lebenszykluszustände und autorisierte Aufrufer erlaubt.
- Saldo-Delta-Buchhaltung auf Gebühren, Rebasings und ungewöhnliches ERC-20-Verhalten testen.
- Nachbedingung jeder Asset-Bewegung prüfen und testen.
Slither kann Muster erkennen wie gefährliche externe Aufrufe, unüberprüfte Rückgabewerte und schwache Zugriffskontrollen, um Validierungsfehler aufzuzeigen. Es kann nicht sämtliche Invarianten des Protokolls ableiten, daher verwenden Sie Foundry-Fuzzing, um Nullwerte, Maximalwerte, doppelte Arrays, unerwartete Adressen und nicht unterstützte Token zu generieren.
Invariante Tests sind besonders wirkungsvoll. Beispielsweise stellen Sie sicher, dass die gesamte ausstehende Schulden niemals das konfigurierte Kreditlimit übersteigt, dass gutgeschriebene Sicherheiten die empfangenen Vermögenswerte nicht übersteigen, und dass nur genehmigte Asset den Buchhaltungsstatus eines Marktes verändern können. Erkunden Sie beim Aufbau eines umfassenden Sicherheitsreviews die Soken Hub, um diese Eigenschaften zu bewerten.
Eingabevalidierung bildet die Grenze zwischen Nutzerabsicht und Protocol-Wahrheit. Ein Vertrag sollte niemals nur auf eine Aussage des Anrufers vertrauen, um eine Gutschrift, Autorisierung, Preisgabe oder Überweisung durchzuführen. Sensible Werte sollten aus verifizierten Zuständen abgeleitet, anerkannte Domänen eingeschränkt und die Invariante enforced werden, die den wirtschaftlichen Zustand sicher hält.
Der nächste praktische Schritt besteht darin, eine Parameter-Invariante-Karte für jede Asset-bewegende Funktion im Code zu erstellen. Jeder Parameter ohne dokumentierte Vertrauensquelle, erlaubten Bereich und Nachbedingung verdient sofortige Prüfung.