Laravel CSRF 保护

Posted

技术标签:

【中文标题】Laravel CSRF 保护【英文标题】:Laravel CSRF protection 【发布时间】:2018-05-27 01:27:58 【问题描述】:

我知道什么是 CSRF 攻击,并且我已经阅读了有关它的文档,但是我无法深入理解 CSRF 保护的工作原理,并且有一些我找不到的一般性问题。

在documentation 中说 Laravel 会自动为

...由应用程序管理的每个活动用户会话。

    它在哪里创建令牌(代码的哪一部分触发它)? 创建后的令牌存储在 cookie 中的什么位置?在会话中?如何提取并查看已存储的内容?这一切实际上是由session.php控制的吗? 这是什么意思,当我重新加载页面时,令牌是否仍与 session.php 相同,默认生命周期为 120 分钟? 如果我将domain 属性设置为"." . env('APP_URL'),当我导航到由同一应用处理的子域时,该cookie 会发生什么情况?

因此,一旦创建令牌并将其存储在某处,当发出请求时,我必须向表单提供 csrf_token() 隐藏属性,或者将其生成为元字段并重定向到我的 JS 文件,如果我是做一个 AJAX 请求。

    那么当我实际发出请求时,底层会发生什么?请求生成csrf_token(),Laravel 对 cookie 进行加密,Laravel 检查发送的 cookie 是否与 session 中的 cookie 相同。如果是,则表示请求有效,如果不是,则抛出TokenMissmatchException

    这是否意味着 cookie 生命周期内的每个请求都将具有相同的令牌?

    Laravel 对请求和响应 cookie 的加密方式不同吗?如果我从 EncryptCookies 类中的 cookie 加密中排除令牌,我会得到相同的令牌,但是当我离开它时,哈希值是不同的。

    在请求数据中提供_token 与作为X-CSRF-TOKEN 标头的转发令牌有何不同?如果我看到它们未加密,Laravel 如何验证它们?他们在请求后会被加密吗?

【问题讨论】:

这里有很多不同的问题,不适用于本网站的格式:虽然答案可能涵盖所有问题,但很容易结束有多个答案,每个答案都涵盖不同的方面,或者页面演变为讨论和修改。如果你能把问题稍微集中一点会更好,必要时可以提出多个问题。 也许这个答案会帮助你了解 csrf ***.com/a/51673924/4701635的内部逻辑 【参考方案1】:
    它在哪里创建令牌(代码的哪一部分触发它)?

查看帮助文件后

/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php

其中定义了csrf_token()辅助方法,它调用了token方法

/vendor/laravel/framework/src/Illuminate/Session/Store.php

如果您检查调用regenerateToken()start(),如果_token 尚未设置,它会使用_token 的密钥将随机40 个字符串保存到会话中

/**
 * Regenerate the CSRF token value.
 *
 * @return void
 */
public function regenerateToken()

    $this->put('_token', Str::random(40));

    创建后的令牌存储在 cookie 中的什么位置?在会话中?如何提取并查看已存储的内容?这一切实际上都是由 session.php 控制的吗?

令牌存储在会话中,您可以使用session('_token') 提取它。会话过期时间控制在session.php 中使用

'lifetime' => env('SESSION_LIFETIME', 120),

'expire_on_close' => false,
    这是什么意思,当我重新加载页面时,令牌仍然与 session.php 的默认生命周期相同吗? 120 分钟?

如果您在/vendor/laravel/framework/src/Illuminate/Session/Store.php 中检查start()

/**
 * Start the session, reading the data from a handler.
 *
 * @return bool
 */
public function start()

    $this->loadSession();

    if (! $this->has('_token')) 
        $this->regenerateToken();
    

    return $this->started = true;

如果会话没有_token,则重新生成令牌。所以_token 在会话到期之前都是一样的

【讨论】:

【参考方案2】:

在我的例子中,从 .env 中删除 APP_URL=http://localhost 解决了 CSRF 令牌的问题。我没有为本地开发人员在 APP_URL 中配置固定值,因为我总是通过浏览器使用不同的主机名,有时还使用端口。

【讨论】:

以上是关于Laravel CSRF 保护的主要内容,如果未能解决你的问题,请参考以下文章

在 Laravel 中设置 CSRF 保护的更好方法是啥?

Laravel CSRF 保护

Laravel CSRF 保护与 REST API

laravel CSRF 保护

laravel5.2总结--csrf保护

Laravel CSRF 保护下的 JQuery AJAX 跨站请求