Heim > Artikel > Backend-Entwicklung > Analyse des CSRF-Verifizierungsprinzips und der Token-Caching-Lösung des Yii2-Frameworks
Dieser Artikel ist hauptsächlich in drei Teile gegliedert. Zunächst wird CSRF kurz vorgestellt, dann wird der Schwerpunkt auf der Analyse des Verifizierungsprinzips des Yii-Frameworks basierend auf dem Quellcode gelegt und schließlich wird eine praktikable Lösung für das durch verursachte Token-Caching vorgeschlagen Seiten-Caching. Die betreffenden Wissenspunkte werden als Anhang am Ende des Artikels angehängt. Interessierte Freunde können es herausfinden.
1. CSRF-Beschreibung
CSRF steht für „Cross-Site Request Forgery“ und ist ein Angriff, der innerhalb der legitimen SITZUNG des Benutzers gestartet wird. Hacker betten schädlichen Web-Request-Code in Webseiten ein und locken Opfer dazu, auf die Seite zuzugreifen. Dabei wird die Anfrage ohne dessen Wissen initiiert und die erwarteten Aktionen des Hackers ausgeführt. Der folgende HTML-Code stellt eine „Produkt löschen“-Funktion bereit:
<a href="http://www.shop.com/delProducts.php?id=100" "javascript:return confirm('Are you sure?')">Delete</a>
Vorausgesetzt, dass der Programmierer im Hintergrund keine entsprechende Legalitätsprüfung der Anfrage „Produkt löschen“ durchführt, solange die Benutzerzugriffe Wenn dieser Link verwendet wird, wird das entsprechende Produkt gelöscht. Anschließend kann der Hacker das Opfer dazu verleiten, eine Webseite mit dem folgenden Schadcode zu besuchen, und dann das entsprechende Produkt ohne Wissen des Opfers löschen.
2.yiis CSRF-Verifizierungsprinzip/vendor/yiisoft/yii2/web/Request.php wird als Request.php abgekürzt
/vendor /yiisoft/yii2/web/Controller.php wird als Controller.php abgekürzt
CSRF-Überprüfung aktivieren
EnableCsrfValidation im Controller auf true setzen , dann ermöglichen alle Vorgänge im Controller die Überprüfung. Der übliche Ansatz besteht darin, „enableCsrfValidation“ auf „false“ zu setzen und einige sensible Vorgänge auf „true“ zu setzen, um eine teilweise Überprüfung zu ermöglichen.
public $enableCsrfValidation = false; /** * @param \yii\base\Action $action * @return bool * @desc: 局部开启csrf验证(重要的表单提交必须加入验证,加入$accessActions即可 */ public function beforeAction($action){ $currentAction = $action->id; $accessActions = ['vote','like','delete','download']; if(in_array($currentAction,$accessActions)) { $action->controller->enableCsrfValidation = true; } parent::beforeAction($action); return true; }
Tokenfeld generieren
In Request.php
zunächst durch die Sicherheit gehen Komponente Sicherheit Eine 32-Bit-Zufallszeichenfolge, die in einem Cookie oder einer Sitzung gespeichert wird.
/** * Generates an unmasked random token used to perform CSRF validation. * @return string the random token for CSRF validation. */ protected function generateCsrfToken() { $token = Yii::$app->getSecurity()->generateRandomString(); if ($this->enableCsrfCookie) { $cookie = $this->createCsrfCookie($token); Yii::$app->getResponse()->getCookies()->add($cookie); } else { Yii::$app->getSession()->set($this->csrfParam, $token); } return $token; }
Anschließend wird durch eine Reihe von Verschlüsselungsersetzungsvorgängen das verschlüsselte _csrfToken generiert. Dies ist das an den Browser übergebene Token. Generieren Sie zunächst zufällig die Zeichenfolgenmaske CSRF_MASK_LENGTH (Standard ist 8 Bits in Yii2) und führen Sie die folgenden Vorgänge für die Maske und das Token aus > ist eine erste Komplement-Bit-XOR-Operation
/** * Returns the XOR result of two strings. * If the two strings are of different lengths, the shorter one will be padded to the length of the longer one. * @param string $token1 * @param string $token2 * @return string the XOR result */ private function xorTokens($token1, $token2) { $n1 = StringHelper::byteLength($token1); $n2 = StringHelper::byteLength($token2); if ($n1 > $n2) { $token2 = str_pad($token2, $n1, $token2); } elseif ($n1 < $n2) { $token1 = str_pad($token1, $n2, $n1 === 0 ? ' ' : $token1); } return $token1 ^ $token2; } public function getCsrfToken($regenerate = false) { if ($this->_csrfToken === null || $regenerate) { if ($regenerate || ($token = $this->loadCsrfToken()) === null) { $token = $this->generateCsrfToken(); } // the mask doesn't need to be very random $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.'; $mask = substr(str_shuffle(str_repeat($chars, 5)), 0, static::CSRF_MASK_LENGTH); // The + sign may be decoded as blank space later, which will fail the validation $this->_csrfToken = str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask))); } return $this->_csrfToken; }
Validierungstokenstr_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask))); $this->xorTokens($arg1,$arg2)
Rufen Sie die Methode „validateCsrfToken“ in request.php in controller.php auf
/** * @inheritdoc */ public function beforeAction($action) { if (parent::beforeAction($action)) { if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) { throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.')); } return true; } return false; } public function validateCsrfToken($token = null) { $method = $this->getMethod(); if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) { return true; } $trueToken = $this->loadCsrfToken();//如果开启了enableCsrfCookie,CsrfToken就从cookie里取,否者从session里取(更安全) if ($token !== null) { return $this->validateCsrfTokenInternal($token, $trueToken); } else { return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken) || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken); } }
Den eingehenden Client abrufen
$this->getBodyParam($this->csrfParam)
und dann validierenCsrfTokenInternal
private function validateCsrfTokenInternal($token, $trueToken) { if (!is_string($token)) { return false; } $token = base64_decode(str_replace('.', '+', $token)); $n = StringHelper::byteLength($token); if ($n <= static::CSRF_MASK_LENGTH) { return false; } $mask = StringHelper::byteSubstr($token, 0, static::CSRF_MASK_LENGTH); $token = StringHelper::byteSubstr($token, static::CSRF_MASK_LENGTH, $n - static::CSRF_MASK_LENGTH); $token = $this->xorTokens($mask, $token); return $token === $trueToken; }
für die Verschlüsselung wird verwendet zur Entschlüsselung 1. Ersetzen Sie zuerst . durch + 2. Dann nehmen Sie mask und mask bzw. this->xorTokens(token,token,mask) entsprechend der Länge heraus this−>xorTokens( this−>xorTokens( token, $mask) Hier heißt es token1 und führt dann die XOR-Operation von mask und token1 aus, um das Token zu erhalten. Beachten Sie, dass beim Verschlüsseln
token1=token^mask
gilt. also beim Entschlüsseln str_replace('+', '.', base64_encode(mask.mask.this->xorTokens(token,token,mask)));
token=mask^token1=mask^(token^mask)
3.Token-Caching-Lösung
Wenn die gesamte Seite zwischengespeichert wird, wird auch das Token zwischengespeichert, was zu einem Überprüfungsfehler führt. Eine übliche Lösung besteht darin, das Token vor jeder Übermittlung erneut abzurufen, damit es die Überprüfung bestehen kann.
Diese Funktion gibt die Eingabe vom linken und vom rechten Ende zurück, nachdem beide Enden gleichzeitig auf die angegebene Länge aufgefüllt wurden mit Leerzeichen, andernfalls wird mit pad_string auf die angegebene Länge aufgefüllt;
verschlüsselt einen String unter Verwendung eines beliebigen Sortierschemas
Da die Verschlüsselung und Entschlüsselung der yii2-CSRF-Verifizierung die XOR-Operation beinhaltet str_pad()
Sie müssen also zunächst die relevanten Kenntnisse der String-XOR-Operation in PHP ergänzen Wenn Sie es nicht benötigen, können Sie es überspringenstr_shuffle()
1 Zeichen können die Ergebnisse direkt berechnet werden, z. B. a^b
in der Tabelle 2. Für mehrere Zeichenfolgen mit derselben Länge berechnet ab^cd das Ergebnis entsprechend a^c und verbindet die Zeichen, die dem Ergebnis entsprechen, das b^d entspricht
Verwandte Tutorials: PHP-Video-Tutorial
Das obige ist der detaillierte Inhalt vonAnalyse des CSRF-Verifizierungsprinzips und der Token-Caching-Lösung des Yii2-Frameworks. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!