Laravel CSRF 保护

2023-04-30 15:17:47 浏览数 (3)

跨站点请求伪造(英语:Cross-site request forgery)是一种恶意利用,利用这种手段,代表经过身份验证的用户执行未经授权的命令。值得庆幸的是,Laravel 可以轻松保护您的应用程序免受跨站点请求伪造(CSRF)攻击。

通过Laravel 用户认证我们知道了web 浏览器认证API 认证,基于此我们今天总结下 CSRF 保护

漏洞的解释

如果您不熟悉跨站点请求伪造,我们讨论一个利用此漏洞的示例。假设您的应用程序有一个 /user/email 路由,它接受 POST 请求来更改经过身份验证用户的电子邮件地址。最有可能的情况是,此路由希望 email 输入字段包含用户希望开始使用的电子邮件地址。

没有 CSRF 保护,恶意网站可能会创建一个 HTML 表单,指向您的应用程序 /user/email 路由,并提交恶意用户自己的电子邮件地址:

代码语言:javascript复制
<form action="https://your-application.com/user/email" method="POST">
    <input type="email" value="malicious-email@example.com">
</form>

<script>
    document.forms[0].submit();
</script>

如果恶意网站在页面加载时自动提交了表单,则恶意用户只需要诱使您的应用程序的一个毫无戒心的用户访问他们的网站,他们的电子邮件地址就会在您的应用程序中更改。

为了防止这种漏洞,我们需要检查每一个传入的 POSTPUTPATCHDELETE 请求以获取恶意应用程序无法访问的秘密会话值。

以上摘自 Laravel 文档;下面自我理解一下:

表单是可以跨域的。

用户打开了浏览器,有两个标签页,一个是您的网站(your-application.com),一个是恶意网站(怎么打开的?可能是短信,E-mail,论坛博客等,诱导用户点击链接打开的)。用户登陆了您的网站,浏览器记录了cookie ,每次请求都会自带 cookie;然后恶意网站,有如上代码(js 自动提交 form 表单),虽然恶意网站不知道你的 cookie,但你的浏览器知道啊,所以自动提交表单时会自动携带 cookie,然后就攻击成功了。

API 应用

没有这玩意。

不依赖 cookies 做安全验证的话,则不需要预防 CSRF。

CSRF 攻击关键在于 cookie,如果 cookie 里不含登陆令牌,你把登录令牌放到 header 里就没问题。因为 CSRF 所利用的 form 和四个特殊 tag 都无法添加 header。现代应用的 API 不接受 form 提交,都是 json 风格的,现代的 web 浏览器都具备 CSP, samesite 等防范机制。

web 浏览器应用

阻止 CSRF 请求

代码语言:javascript复制
<form method="POST" action="/profile">
    @csrf

    <!-- 等同于... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

从 CSRF 保护中排除 URI

再次强调一下,只有用到web中间件组了,Csrf验证才会生效,也才需要禁用;比如api应用用不到web中间件组,就不用理会。

全局禁用,(当然这是不推荐的),注释掉AppHttpMiddlewareVerifyCsrfToken::class中间件

代码语言:javascript复制
<?php

namespace AppHttp;

use IlluminateFoundationHttpKernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
//            AppHttpMiddlewareVerifyCsrfToken::class,
        ],

排除部分链接,比如支付回调等

代码语言:javascript复制
<?php

namespace AppHttpMiddleware;

use IlluminateFoundationHttpMiddlewareVerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * 从 CSRF 验证中排除的 URI。
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}

1 人点赞