为什么token和XSRF-token在Laravel中有所不同?
我不明白为什么AJAX请求的令牌(XSRF-token)与普通表单使用的为什么token和XSRF-token在Laravel中有所不同?,laravel,csrf,websecurity,Laravel,Csrf,Websecurity,我不明白为什么AJAX请求的令牌(XSRF-token)与普通表单使用的\u令牌不同。此外,它要长得多。为什么?为什么有两个代币呢?为什么不使用一个对ajax和普通请求都相同的方法呢?如果您查看一下vendor/laravel/framework/src/illighte/Session/Store.php有一个名为regenerateToken的方法,它将为应用程序生成令牌 /** *重新生成CSRF令牌值。 * *@返回无效 */ 公共函数令牌() { $this->put('u token
\u令牌
不同。此外,它要长得多。为什么?为什么有两个代币呢?为什么不使用一个对ajax和普通请求都相同的方法呢?如果您查看一下vendor/laravel/framework/src/illighte/Session/Store.php
有一个名为regenerateToken
的方法,它将为应用程序生成令牌
/**
*重新生成CSRF令牌值。
*
*@返回无效
*/
公共函数令牌()
{
$this->put('u token',Str::random(40));
}
然后,您从会话
或JS
(也是从会话中获得的)获得的令牌,它们都具有相同的40个字符长度,并且令牌只是存储在会话中的一个简单的随机40个字符。它没有加密或散列,因为只有你,用户才有权访问会话,因为如果我想从任何外部源进行CSRF攻击,则源没有访问会话的权限,因此基本上不需要散列或加密40长度的令牌
旁注:令牌本身不加密,默认情况下,所有会话都在laravel中加密。以下是有关XSRF的文档说明: 因此,基本上,加密并保存在cookies中的_令牌的值是相同的1方法,2 Laravel使用两种不同的技术来防止CSRF攻击 方法相同: 要向客户端发送令牌(CSRF或XSRF),客户端必须返回 它在以下请求中返回 有两个步骤:
- 服务器发送令牌(获取表单)(CSRF或XSRF)
- 作为X-token的客户端返回令牌(发布表单)(X-CSRF或X-XSRF)
- 旧方式:服务器生成纯html并将其发送给客户端
- 单页应用程序:客户端SPA框架(如Vue、React、Angular)以Json或Xml的形式发送和接收数据,并在Dom中创建适当的Html
+-------------+-----------------+-----------+------------+
| Client Arch | Protection Tech | Get Token | Post Token |
+-------------+-----------------+-----------+------------+
| old-fashion | sync-token | CSRF | X-CSRF |
| SPA | cookie-header | XSRF | X-XSRF |
+-------------+-----------------+-----------+------------+
机构描述
1.服务器生成令牌
Laravel制作一个CSRF令牌(40个字符)并将其存储在会话中
/**
* Regenerate the CSRF token value.
*
* @return void
*/
public function regenerateToken()
{
$this->put('_token', Str::random(40));
}
在会话中生成并存储令牌后,令牌将作为CSRF和XSRF发送到客户端
客户端将决定使用它想要的任何东西
2.服务器向客户端发送令牌
对于老式的(同步令牌技术),客户端可以通过调用刀片中的CSRF\u token()
helper方法以两种形式接收CSRF令牌:
/**
* Get the CSRF token value.
*
* @return string
*
* @throws \RuntimeException
*/
function csrf_token()
{
$session = app('session');
if (isset($session)) {
return $session->token();
}
throw new RuntimeException('Application session store not set.');
}
对于cookie头(SPA框架),客户端框架(如Angular)可以在cookie中接收XSRF令牌,因为:
服务器中没有生成可由服务器进行种子设定的Html表单
它的隐藏输入。以及它将代币发送给
客户端正在用cookie发送它。(此方法名为XSRF)
Laravel将令牌放在这两个地方,因为这取决于客户机使用哪种方法,并期望客户机响应其中一种方法
3.客户端向服务器发送X令牌
在客户端:
- post数据中的post令牌或:
- 进行如下ajax调用:
现在是时候拉威尔检查代币了 在VerifyCSRFMiddleware中,Laravel检查请求是否应为其检查的CSRF保护令牌:
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*
* @throws \Illuminate\Session\TokenMismatchException
*/
public function handle($request, Closure $next)
{
if (
$this->isReading($request) ||
$this->runningUnitTests() ||
$this->inExceptArray($request) ||
$this->tokensMatch($request) //compares request_token vs session_token
) {
return tap($next($request), function ($response) use ($request) {
if ($this->shouldAddXsrfTokenCookie()) {
$this->addCookieToResponse($request, $response); //add cookie to response
}
});
}
throw new TokenMismatchException('CSRF token mismatch.');
}
其中有两条线值得关注:
$this->tokensMatch($request)
及
因此,服务器可以在每个请求中放置多个数据:
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);// it get token from request
return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token); //checks if it is equal to session token or not
}
/**
* Get the CSRF token from the request.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function getTokenFromRequest($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');//check sync-token
if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
}
return $token;
}
要检查的第一个模式是sync token,来自客户端的token可以位于
中,如果从客户端的Ajax方法调用请求,也可以位于Http头中
线路
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
将对此进行检查,如果可以检索,它将返回并通过会话\u令牌进行检查
但是如果(!$token
为NULL
它将根据cookie头模式进行检查:
从报头获取$header=$request->header('X-XSRF-TOKEN')
,并在需要解密时对其进行解密
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
如果在添加到cookie之前对其进行了加密
Cookie加密
这就是XSRF令牌可以是224个字符的原因:
Cookie加密
您可以禁用cookie加密,并将XSRF令牌设置为40个字符,就像CSRF令牌一样
所以区别在于Cookie加密
Cookie加密的必要性
但是为什么Cookie需要加密?为什么XSRF Cookie需要加密???
总的来说,拉威尔
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);// it get token from request
return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token); //checks if it is equal to session token or not
}
/**
* Get the CSRF token from the request.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function getTokenFromRequest($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');//check sync-token
if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
}
return $token;
}
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));