goo*_*ing 5 csrf laravel websecurity
我不明白为什么 AJAX 请求 (XSRF-TOKEN) 的令牌与_token正常表单使用的令牌不同。此外,它更长。为什么?为什么有 2 个令牌呢?为什么不使用一个对 ajax 和普通请求都相同的请求?
Abi*_*gos 11
Laravel 使用 2 种不同的技术来防止 CSRF 攻击。
方法是相同的:
向客户端发送令牌(CSRF 或 XSRF),并且客户端必须在以下请求中将其返回
有两个步骤:
当您看到 X- 令牌时,它是客户端通过 Post 发送到服务器的客户端回复
我们拥有两种技术的原因不是它们使用不同的方法,
这是因为 Web 应用程序客户端架构使用 2 种不同的架构:
现在 CSRF-Protection Technics 适应了这两种客户端架构,如下所示:
+-------------+-----------------+-----------+------------+
| Client Arch | Protection Tech | Get Token | Post Token |
+-------------+-----------------+-----------+------------+
| old-fashion | sync-token | CSRF | X-CSRF |
| SPA | cookie-header | XSRF | X-XSRF |
+-------------+-----------------+-----------+------------+
Run Code Online (Sandbox Code Playgroud)
Laravel 制作一个 CSRF 令牌(40 个字符)并将其存储在会话中
/**
* Regenerate the CSRF token value.
*
* @return void
*/
public function regenerateToken()
{
$this->put('_token', Str::random(40));
}
Run Code Online (Sandbox Code Playgroud)
在会话中生成并存储令牌后,令牌将作为 CSRF 和 XSRF 发送到客户端
客户端将决定使用它想要的任何内容。
对于老式(同步令牌技术)客户端可以通过调用csrf_token()blade中的帮助器方法以两种形式接收CSRF令牌:
<input type='hidden' name='_token' value='{{csrf_token()}}' />下面是这个辅助方法如何返回相应的值:
/**
* 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.');
}
Run Code Online (Sandbox Code Playgroud)
对于 cookie-header(SPA 框架)客户端框架(如 Angular)可以在 Cookie 中接收 XSRF 令牌,因为:
服务器中没有生成 Html 表单,服务器可以在其中播种其隐藏输入。它可以将其令牌发送给客户端的方式是使用 cookie 发送它。(此方法名为XSRF)
/**
* Add the CSRF token to the response cookies.
*
* @param \Illuminate\Http\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function addCookieToResponse($request, $response)
{
$config = config('session');
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
)
);
return $response;
}
Run Code Online (Sandbox Code Playgroud)
Laravel 将令牌放在两个地方,因为由客户端决定使用哪种方法,并期望客户端响应其中一种方法。
在客户端:
`$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});`
Run Code Online (Sandbox Code Playgroud)
SPA 框架:这些框架将令牌作为 X-XSRF-TOKEN 放在帖子标题中
服务器检查 X- 令牌与会话中令牌
现在是 Laravel 检查令牌的时候了
在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.');
}
Run Code Online (Sandbox Code Playgroud)
其中两行很有趣:
$this->tokensMatch($request)
Run Code Online (Sandbox Code Playgroud)
和
$this->addCookieToResponse($request, $response);
Run Code Online (Sandbox Code Playgroud)
因此服务器可以在每个请求中放置多个数据:
客户端可以将多个数据发送到服务器作为对令牌的响应
为什么 CSRF 令牌是 40 个字符,而 XSRF 是 224 个字符?我们稍后会谈到这个
Http 请求必须将令牌与上述X 令牌之一相匹配
/**
* 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;
}
Run Code Online (Sandbox Code Playgroud)
要检查的第一个模式是同步令牌,来自客户端的令牌可以位于Http 标头中,如果从客户端中的 Ajax 方法调用请求,也<input name='_token' />可以位于Http 标头中。
线
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
Run Code Online (Sandbox Code Playgroud)
将检查它,如果可以检索,它将返回并通过 session_token 检查
但if (! $token它NULL会检查 cookie 标头模式:
从标头获取$header = $request->header('X-XSRF-TOKEN')并解密它(如果需要解密)
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
Run Code Online (Sandbox Code Playgroud)
在添加到 cookie 之前是否已加密
这就是 XSRF 令牌可能为 224 个字符的原因: Cookie 加密 ,您可以禁用 cookie 加密并使 XSRF 令牌为 40 个字符,就像 CSRF 令牌一样
所以区别在于 Cookie 加密。
但为什么 Cookie 需要加密?为什么 XSRF Cookie 需要加密?
一般来说,Laravel 会在 cookie 上存储一些数据,并且 cookie 可以由客户端修改。因为服务器不希望客户端进行修改,所以它对Cookie 进行加密。可以将其配置为不加密 CSRF Cookie,因为它不会被用户更改,并且只会被cookie 劫持窃取,而加密不会阻止此事件。
其唯一的区别是必须为两种 CSRF 保护方法提供令牌(未加密和加密)。因此,如果攻击者可以访问cookie 存储的(X-XSRF) 令牌(因为劫持 > Cookie 更容易使用 XSS 劫持运行时 html 和 css),则不能滥用同步令牌机制。由于使用 http-form 参数进行 CSRF 攻击更容易,因为 html 可以在电子邮件等中,而 Runnig Js 不太常见。
因此,如果客户使用老式客户端架构师。cookie 标头技术 >(XSRF 存储在 Cookie 中)不会让他在 cookie 中出现数据泄漏。
有关这种预防模式的更多信息可以在这里找到:
https://en.wikipedia.org/wiki/Cross-site_request_forgery#Prevention
| 归档时间: |
|
| 查看次数: |
973 次 |
| 最近记录: |