mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-04 06:37:55 +08:00 
			
		
		
		
	Added CSRF support.
This commit is contained in:
		@ -293,12 +293,16 @@ class Html
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		$hiddenInputs = array();
 | 
							$hiddenInputs = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$request = Yii::$app->getRequest();
 | 
				
			||||||
 | 
							if ($request instanceof Request) {
 | 
				
			||||||
			if (strcasecmp($method, 'get') && strcasecmp($method, 'post')) {
 | 
								if (strcasecmp($method, 'get') && strcasecmp($method, 'post')) {
 | 
				
			||||||
				// simulate PUT, DELETE, etc. via POST
 | 
									// simulate PUT, DELETE, etc. via POST
 | 
				
			||||||
			if (($request = Yii::$app->getRequest()) instanceof Request) {
 | 
					 | 
				
			||||||
				$hiddenInputs[] = static::hiddenInput($request->restVar, $method);
 | 
									$hiddenInputs[] = static::hiddenInput($request->restVar, $method);
 | 
				
			||||||
				$method = 'post';
 | 
									$method = 'post';
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if ($request->enableCsrfValidation) {
 | 
				
			||||||
 | 
									$hiddenInputs[] = static::hiddenInput($request->csrfTokenName, $request->getCsrfToken());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!strcasecmp($method, 'get') && ($pos = strpos($action, '?')) !== false) {
 | 
							if (!strcasecmp($method, 'get') && ($pos = strpos($action, '?')) !== false) {
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,27 @@ use yii\base\InvalidConfigException;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class Request extends \yii\base\Request
 | 
					class Request extends \yii\base\Request
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to false.
 | 
				
			||||||
 | 
						 * By setting this property to true, forms submitted to an Yii Web application must be originated
 | 
				
			||||||
 | 
						 * from the same application. If not, a 400 HTTP exception will be raised.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Note, this feature requires that the user client accepts cookie. Also, to use this feature,
 | 
				
			||||||
 | 
						 * forms submitted via POST method must contain a hidden input whose name is specified by [[csrfTokenName]].
 | 
				
			||||||
 | 
						 * You may use [[\yii\web\Html::beginForm()]] to generate his hidden input.
 | 
				
			||||||
 | 
						 * @see http://en.wikipedia.org/wiki/Cross-site_request_forgery
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public $enableCsrfValidation = false;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @var string the name of the token used to prevent CSRF. Defaults to 'YII_CSRF_TOKEN'.
 | 
				
			||||||
 | 
						 * This property is effectively only when {@link enableCsrfValidation} is true.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public $csrfTokenName = '_csrf';
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @var array the configuration of the CSRF cookie. This property is used only when [[enableCsrfValidation]] is true.
 | 
				
			||||||
 | 
						 * @see Cookie
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public $csrfCookie = array('httponly' => true);
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to true.
 | 
						 * @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to true.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@ -35,6 +56,7 @@ class Request extends \yii\base\Request
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	private $_cookies;
 | 
						private $_cookies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Resolves the current request into a route and the associated parameters.
 | 
						 * Resolves the current request into a route and the associated parameters.
 | 
				
			||||||
	 * @return array the first element is the route, and the second is the associated parameters.
 | 
						 * @return array the first element is the route, and the second is the associated parameters.
 | 
				
			||||||
@ -42,6 +64,8 @@ class Request extends \yii\base\Request
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public function resolve()
 | 
						public function resolve()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							$this->validateCsrfToken();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		$result = Yii::$app->getUrlManager()->parseRequest($this);
 | 
							$result = Yii::$app->getUrlManager()->parseRequest($this);
 | 
				
			||||||
		if ($result !== false) {
 | 
							if ($result !== false) {
 | 
				
			||||||
			list ($route, $params) = $result;
 | 
								list ($route, $params) = $result;
 | 
				
			||||||
@ -699,5 +723,72 @@ class Request extends \yii\base\Request
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return $this->_cookies;
 | 
							return $this->_cookies;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private $_csrfToken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns the random token used to perform CSRF validation.
 | 
				
			||||||
 | 
						 * The token will be read from cookie first. If not found, a new token will be generated.
 | 
				
			||||||
 | 
						 * @return string the random token for CSRF validation.
 | 
				
			||||||
 | 
						 * @see enableCsrfValidation
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public function getCsrfToken()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if ($this->_csrfToken === null) {
 | 
				
			||||||
 | 
								$cookies = $this->getCookies();
 | 
				
			||||||
 | 
								if (($this->_csrfToken = $cookies->getValue($this->csrfTokenName)) === null) {
 | 
				
			||||||
 | 
									$cookie = $this->createCsrfCookie();
 | 
				
			||||||
 | 
									$this->_csrfToken = $cookie->value;
 | 
				
			||||||
 | 
									$cookies->add($cookie);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return $this->_csrfToken;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates a cookie with a randomly generated CSRF token.
 | 
				
			||||||
 | 
						 * Initial values specified in [[csrfCookie]] will be applied to the generated cookie.
 | 
				
			||||||
 | 
						 * @return Cookie the generated cookie
 | 
				
			||||||
 | 
						 * @see enableCsrfValidation
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						protected function createCsrfCookie()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							$options = $this->csrfCookie;
 | 
				
			||||||
 | 
							$options['name'] = $this->csrfTokenName;
 | 
				
			||||||
 | 
							$options['value'] = sha1(uniqid(mt_rand(), true));
 | 
				
			||||||
 | 
							return new Cookie($options);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Performs the CSRF validation.
 | 
				
			||||||
 | 
						 * The method will compare the CSRF token obtained from a cookie and from a POST field.
 | 
				
			||||||
 | 
						 * If they are different, a CSRF attack is detected and a 400 HTTP exception will be raised.
 | 
				
			||||||
 | 
						 * @throws HttpException if the validation fails
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public function validateCsrfToken()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!$this->enableCsrfValidation) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							$method = $this->getRequestMethod();
 | 
				
			||||||
 | 
							if ($method === 'POST' || $method === 'PUT' || $method === 'DELETE') {
 | 
				
			||||||
 | 
								$cookies = $this->getCookies();
 | 
				
			||||||
 | 
								switch ($method) {
 | 
				
			||||||
 | 
									case 'POST':
 | 
				
			||||||
 | 
										$token = $this->getPost($this->csrfTokenName);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case 'PUT':
 | 
				
			||||||
 | 
										$token = $this->getPut($this->csrfTokenName);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case 'DELETE':
 | 
				
			||||||
 | 
										$token = $this->getDelete($this->csrfTokenName);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (empty($token) || $cookies->getValue($this->csrfTokenName) !== $token) {
 | 
				
			||||||
 | 
									throw new HttpException(400, Yii::t('yii|Unable to verify your data submission.'));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -56,7 +56,7 @@ class User extends Component
 | 
				
			|||||||
	 * @var array the configuration of the identity cookie. This property is used only when [[enableAutoLogin]] is true.
 | 
						 * @var array the configuration of the identity cookie. This property is used only when [[enableAutoLogin]] is true.
 | 
				
			||||||
	 * @see Cookie
 | 
						 * @see Cookie
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public $identityCookie = array('name' => '__identity', 'httponly' => true);
 | 
						public $identityCookie = array('name' => '_identity', 'httponly' => true);
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @var integer the number of seconds in which the user will be logged out automatically if he
 | 
						 * @var integer the number of seconds in which the user will be logged out automatically if he
 | 
				
			||||||
	 * remains inactive. If this property is not set, the user will be logged out after
 | 
						 * remains inactive. If this property is not set, the user will be logged out after
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user