Maison > Article > développement back-end > Analyse du principe de vérification csrf et de la solution de mise en cache des jetons du framework Yii2
Cet article est principalement divisé en trois parties. Premièrement, il présente brièvement CSRF, puis se concentre sur l'analyse du principe de vérification du framework Yii basé sur le code source, et propose enfin une solution réalisable pour la mise en cache des jetons causée par mise en cache des pages. Les points de connaissances concernés seront joints en annexe à la fin de l’article. Les amis intéressés peuvent le découvrir.
1. Description CSRF
CSRF signifie "Cross-Site Request Forgery" et est une attaque lancée au cours de la SESSION légitime de l'utilisateur. Les pirates intègrent un code de requête Web malveillant dans des pages Web et incitent les victimes à accéder à la page. Lors de l'accès à la page, la demande est lancée sous l'identité juridique de la victime, à son insu, et les actions attendues du pirate informatique sont exécutées. Le code HTML suivant fournit une fonction « supprimer le produit » :
<a href="http://www.shop.com/delProducts.php?id=100" "javascript:return confirm('Are you sure?')">Delete</a>
En supposant que le programmeur n'effectue pas la vérification de légalité correspondante sur la demande de « suppression du produit » en arrière-plan, tant en tant qu'utilisateur Après avoir visité ce lien, le produit correspondant sera supprimé. Le pirate informatique peut alors tromper la victime en lui faisant visiter une page Web avec le code malveillant suivant, puis supprimer le produit correspondant à l'insu de la victime.
Le principe de vérification csrf de 2.yii/vendor/yiisoft/yii2/web/Request.php est abrégé en Request.php
/vendor /yiisoft/yii2/web/Controller.php est abrégé en Controller.php
Activer la vérification csrf
Définissez activateCsrfValidation sur true dans le contrôleur , alors toutes les opérations dans le contrôleur permettront la vérification. L'approche habituelle consiste à définir activateCsrfValidation sur false et à définir certaines opérations sensibles sur true pour activer la vérification partielle.
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; }
Générer le champ de jeton
dans Request.php
passez d'abord la sécurité Le composant Security obtient une chaîne aléatoire de 32 bits et la stocke dans un cookie ou une session. Il s'agit d'un jeton natif
/** * 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; }
Ensuite, grâce à une série d'opérations de remplacement de chiffrement, le chiffrement_. csrfToken, c'est le jeton transmis au navigateur. Générez d'abord aléatoirement le masque de chaîne de longueur CSRF_MASK_LENGTH (la valeur par défaut est de 8 bits dans Yii2)
et effectuez les opérations suivantes sur le masque et le jeton str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask))); $this->xorTokens($arg1,$arg2)
/** * 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; }. 🎜> Il s'agit d'une opération XOR de premier remplissage
Jeton de vérification
/** * @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); } }Appelez la méthode validateCsrfToken dans request.php dans le contrôleur. php
$this->getBodyParam($this->csrfParam)Obtenez le client entrant
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; }puis validezCsrfTokenInternal
str_replace('+', '.', base64_encode(mask.mask.this->xorTokens(token,token,mask)));
token1=token^maskDécryptage 1. Remplacez d'abord . par + 2. Puis base64_decode puis retirez masque et masque et this->xorTokens(token,token,mask) selon la longueur respectivement pour la commodité de ; explication this−>xorTokens(this−>xorTokens(token, $mask) est ici appelé token1 puis effectuez l'opération XOR de mask et token1 pour obtenir le jeton. Notez que lors du cryptage
token=mask^token1=mask^(token^mask)Ainsi lors du décryptage
3.Solution de mise en cache des jetons
Lorsque la page entière est mise en cache, le jeton est également mis en cache. La mise en cache provoque l'échec de la vérification. Une solution courante consiste à réobtenir le jeton avant chaque soumission, afin que la vérification puisse réussir , cette fonction renvoie le résultat de l'entrée complétée au spécifié. length à partir de l'extrémité gauche, de l'extrémité droite ou des deux extrémités. Si le paramètre facultatif pad_string n'est pas spécifié, l'entrée sera complétée par des espaces, sinon elle sera complétée par pad_string à la longueur spécifiée ; La fonction 🎜>
brouille une chaîne, en utilisant n'importe quel schéma de tri possible. Le cryptage et le déchiffrement de la vérification yii2 csrf impliquent une opération XOR str_pad()
, vous devez donc le faire. Complétez d'abord les connaissances pertinentes sur l'opération XOR de chaîne en PHP. Si vous n'en avez pas besoin, vous pouvez ignorer str_shuffle()
1. Pour un seul caractère et un seul caractère, le résultat peut être directement calculé, comme a^b
dans le tableau 2. comme ab^cd dans le tableau, calculer le résultat correspondant à a^c et concaténer les caractères correspondant au résultat correspondant à b^d
Tutoriels associés : Tutoriel vidéo PHP
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!