Hallo, ich habe Solidity-Dokumentation durchgesehen. Es gab einige Codes, die ich nicht verstehen konnte, selbst nachdem ich viel recherchiert hatte, konnte ich keine zufriedenstellende Ausgabe finden. Der Code lautet wie folgt:
contract Mutex {
bool locked;
modifier noReentrancy() {
require(!locked);
locked = true;
_;
locked = false;
}
/// This function is protected by a mutex, which means that
/// reentrant calls from within `msg.sender.call` cannot call `f` again.
/// The `return 7` statement assigns 7 to the return value but still
/// executes the statement `locked = false` in the modifier.
function f() public noReentrancy returns (uint) {
require(msg.sender.call());
return 7;
}
}
Was msg.sender.call()
bedeutet? ruft es f()
wieder an? Wenn ja, wie dann?
Es ruft die anonyme Fallback-Funktion auf auf msg.sender
.
Bei einem typischen Reentrancy-Angriff wäre es so etwas wie eine withdraw
Funktion, die msg.sender.call.value(1 ether)()
. Der Aufrufer (ein intelligenter Vertrag) würde die Funktion dann erneut aufrufen, daher der "Reentrancy" -Angriff. In diesem Snippet call
scheint das nichts Nützliches zu tun, aber es ist nur dazu da, um zu zeigen, dass die locked
Variablen vor Wiedereintritt schützen.
msg.sender.call()
ruft die Fallback-Funktion auf auf msg.sender
.
Hier ist ein Beispiel, das um eine canBeAttacked
Funktion erweitert wird.
contract Mutex {
bool locked;
modifier noReentrancy() {
require(!locked);
locked = true;
_;
locked = false;
}
function canBeAttacked() public returns (uint) {
require(msg.sender.call.value(1 ether)());
return 7;
}
/// This function is protected by a mutex
function f() public noReentrancy returns (uint) {
require(msg.sender.call());
return 7;
}
}
2 Dinge, die Sie aus dem obigen Code beachten sollten.
von:
// attacker fallback
function() {
Mutex(msg.sender).canBeAttacked();
}
Der Vertrag kann eine andere Funktion haben, die aufruft canBeAttacked()
, und diese wird immer wieder neu betreten canBeAttacked()
und dem Angreifer jedes Mal 1 Ether senden. (Der Fallback benötigt mehr Code, um eine Endlosschleife und ein Auslaufen des Gases zu vermeiden.) Dies ist ein Beispiel für einen reentranten Angriff.
Stellen Sie sich nun einen Angreifervertrag vor, der einen Fallback von hat:
// attacker fallback
function() {
Mutex(msg.sender).f();
}
f()
, schlägt der Angreifer-Fallback fehl, da , also locked
eine Ausnahme generiert und die gesamte Transaktion rückgängig macht.true
require(!locked)
Beachten Sie auch, dass noReentrancy
verhindert wird, dass ein Angreifer anruft f()
und im Fallback des Angreifers canBeAttacked
. (Aber sie können wie Nr. 1 oben angreifen.)
eth