Heim  >  Artikel  >  Backend-Entwicklung  >  Analyse des CSRF-Verifizierungsprinzips und der Token-Caching-Lösung des Yii2-Frameworks

Analyse des CSRF-Verifizierungsprinzips und der Token-Caching-Lösung des Yii2-Frameworks

little bottle
little bottlenach vorne
2019-04-25 15:20:012242Durchsuche

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(&#39;Are you sure?&#39;)">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 = [&#39;vote&#39;,&#39;like&#39;,&#39;delete&#39;,&#39;download&#39;];
    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 ? &#39; &#39; : $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&#39;t need to be very random
        $chars = &#39;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.&#39;;
        $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(&#39;+&#39;, &#39;.&#39;, 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(&#39;yii&#39;, &#39;Unable to verify your data submission.&#39;));
        }
        return true;
    }
    
    return false;
}
public function validateCsrfToken($token = null)
{
    $method = $this->getMethod();
    if (!$this->enableCsrfValidation || in_array($method, [&#39;GET&#39;, &#39;HEAD&#39;, &#39;OPTIONS&#39;], 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(&#39;.&#39;, &#39;+&#39;, $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()

^Wenn die XOR-Operation unterschiedlich ist, wird 1 zurückgegeben. Nein oder 0 wird zurückgegeben. In der PHP-Sprache wird es häufig zur Verschlüsselung verwendet Zur Entschlüsselung wird auch direkt der ASCII-Code des Zeichens in einen Binärcode umgewandelt.

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen