Cross-site request forgery (English: Cross-site request forgery), also known as one-click attack or session riding, usually abbreviated as CSRF or XSRF, is a kind of blackmailing users An attack method that performs unintended operations on the currently logged-in web application.
Cross-site request attack, simply put, is when the attacker uses some technical means to trick the user's browser into accessing a website that he has authenticated and running it Some operations (such as sending emails, sending messages, and even property operations such as transferring money and purchasing goods). (Recommended learning: yii framework)
Since the browser has been authenticated, the visited website will consider it to be a real user operation and run it.
This takes advantage of a vulnerability in user authentication in the web: simple authentication can only guarantee that the request comes from a certain user's browser, but cannot guarantee that the request itself is voluntarily issued by the user.
yii2’s csrf, here is a brief introduction to its verification mechanism.
Get the token value used for csrf verification; determine whether the token used for csrf exists. If it does not exist, use generateCsrfToken() to generate it.
Verify that the beforeAction() method in web\Controller has Yii::$app->getRequest()->validateCsrfToken() judgment, which is used to verify csrf.
Generally, my understanding of yii2’s csrf starts with Yii::$app->request->getCsrfToken(); OK, let’s start with getCsrfToken(). This method is in yii\web\Request.php:
/** * Returns the token used to perform CSRF validation. * 返回用于执行CSRF验证的token * This token is a masked version of [[rawCsrfToken]] to prevent [BREACH attacks](http://breachattack.com/). * This token may be passed along via a hidden field of an HTML form or an HTTP header value * to support CSRF validation. * @param boolean $regenerate whether to regenerate CSRF token. When this parameter is true, each time * this method is called, a new CSRF token will be generated and persisted (in session or cookie). * @return string the token used to perform CSRF validation. */ public function getCsrfToken($regenerate = false) { if ($this->_csrfToken === null || $regenerate) { if ($regenerate || ($token = $this->loadCsrfToken()) === null) { //loadCsrfToken()就是在cookie或者session中获取token值 $token = $this->generateCsrfToken(); //如果token为空则调用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; } /** * Loads the CSRF token from cookie or session. * @return string the CSRF token loaded from cookie or session. Null is returned if the cookie or session * does not have CSRF token. */ protected function loadCsrfToken() { if ($this->enableCsrfCookie) { return $this->getCookies()->getValue($this->csrfParam); //cookie中获取csrf的token } else { return Yii::$app->getSession()->get($this->csrfParam); //session中获取csrf的token } } /** * Creates a cookie with a randomly generated CSRF token. * Initial values specified in [[csrfCookie]] will be applied to the generated cookie. * @param string $token the CSRF token * @return Cookie the generated cookie * @see enableCsrfValidation */ protected function createCsrfCookie($token) { $options = $this->csrfCookie; $options['name'] = $this->csrfParam; $options['value'] = $token; return new Cookie($options); } /** * 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); //createCsrfCookie()用于生成csrf的key=>value形式的token Yii::$app->getResponse()->getCookies()->add($cookie); //将生成key=>value保存到cookies } else { Yii::$app->getSession()->set($this->csrfParam, $token); //将csrf的token存在session中 } return $token; } /** * 每次调用控制器中的方法的时候都会调用下面的Yii::$app->getRequest()->validateCsrfToken()验证 * @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; } else { return false; } } /** * 校验方法 * Performs the CSRF validation. * * This method will validate the user-provided CSRF token by comparing it with the one stored in cookie or session. * This method is mainly called in [[Controller::beforeAction()]]. * * Note that the method will NOT perform CSRF validation if [[enableCsrfValidation]] is false or the HTTP method * is among GET, HEAD or OPTIONS. * * @param string $token the user-provided CSRF token to be validated. If null, the token will be retrieved from * the [[csrfParam]] POST field or HTTP header. * This parameter is available since version 2.0.4. * @return boolean whether CSRF token is valid. If [[enableCsrfValidation]] is false, this method will return true. */ public function validateCsrfToken($token = null) { $method = $this->getMethod(); // only validate CSRF token on non-"safe" methods http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) { return true; } $trueToken = $this->loadCsrfToken(); if ($token !== null) { return $this->validateCsrfTokenInternal($token, $trueToken); } else { return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken) || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken); //getCsrfTokenFromHeader()这个我也不太理解,还请指点一下 } } /** * @return string the CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned if no such header is sent. */ public function getCsrfTokenFromHeader() { $key = 'HTTP_' . str_replace('-', '_', strtoupper(static::CSRF_HEADER)); return isset($_SERVER[$key]) ? $_SERVER[$key] : null; } /** * Validates CSRF token * * @param string $token * @param string $trueToken * @return boolean */ private function validateCsrfTokenInternal($token, $trueToken) { $token = base64_decode(str_replace('.', '+', $token)); //解码从客户端获取的csrf的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; //验证从客户端获取的csrf的token和真实的token是否相等 }
The above is the detailed content of What is yii csrf. For more information, please follow other related articles on the PHP Chinese website!