<article><h1>Laravel 下的伪造跨站请求保护 CSRF</h1><ul><li><a href="#csrf-introduction">简介</a></li><li><a href="#csrf-excluding-uris">CSRF 白名单</a></li><li><a href="#csrf-x-csrf-token">X-CSRF-Token</a></li><li><a href="#csrf-x-xsrf-token">X-XSRF-Token</a></li></ul><p><a name="csrf-introduction"></a></p><h2><a href="#csrf-introduction">简介</a></h2><p>Laravel 提供了简单的方法使你的应用免受 <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">跨站请求伪造</a> (CSRF) 的袭击。跨站请求伪造是一种恶意的攻击,它凭借已通过身份验证的用户身份来运行未经过授权的命令。</p><p>Laravel 为每个活跃用户的 Session 自动生成一个 CSRF 令牌。该令牌用来核实应用接收到的请求是通过身份验证的用户出于本意发送的。</p><p>任何情况下在你的应用程序中定义 HTML 表单时都应该包含 CSRF 令牌隐藏域,这样 CSRF 保护中间件才可以验证请求。辅助函数 <code class=" language-php">csrf_field</code> 可以用来生成令牌字段:</p><pre class=" language-php"><code class=" language-php"><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/profile<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">csrf_field<span class="token punctuation">(</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></span></span></span></code></pre><p>包含在 <code class=" language-php">web</code> 中间件组里的 <code class=" language-php">VerifyCsrfToken</code> <a href="/docs/5.4/middleware">中间件</a>会自动验证请求里的令牌 <code class=" language-php">token</code> 与 Session 中存储的令牌 <code class=" language-php">token</code> 是否匹配。</p><p><a name="csrf-excluding-uris"></a></p><h2><a href="#csrf-excluding-uris">CSRF 白名单</a></h2><p>有时候你可能希望设置一组并不需要 CSRF 保护的 URI。例如,如果你正在使用 <a href="https://stripe.com">Stripe</a> 处理付款并使用了他们的 webhook 系统,你会需要将 Stripe webhook 处理的路由排除在 CSRF 保护外,因为 Stripe 并不知道发送给你路由的 CSRF 令牌是什么。</p><p>一般地,你可以把这类路由放到 <code class=" language-php">web</code> 中间件外,因为 <code class=" language-php">RouteServiceProvider</code> 适用于 <code class=" language-php">routes<span class="token operator">/</span>web<span class="token punctuation">.</span>php</code> 中的所有路由。不过如果一定要这么做,你也可以将这类 URI 添加到 <code class=" language-php">VerifyCsrfToken</code> 中间件中的 <code class=" language-php"><span class="token variable">$except</span></code> 属性来排除对这类路由的 CSRF 保护:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>VerifyCsrfToken</span> <span class="token keyword">as</span> BaseVerifier<span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">VerifyCsrfToken</span> <span class="token keyword">extends</span> <span class="token class-name">BaseVerifier</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 这些 URI 会被免除 CSRF 验证
*
* @var array
*/</span>
<span class="token keyword">protected</span> <span class="token variable">$except</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token string">'stripe/*'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><p><a name="csrf-x-csrf-token"></a></p><h2><a href="#csrf-x-csrf-token">X-CSRF-TOKEN</a></h2><p>除了检查 POST 参数中的 CSRF token 外,<code class=" language-php">VerifyCsrfToken</code> 中间件还会检查 <code class=" language-php">X<span class="token operator">-</span><span class="token constant">CSRF</span><span class="token operator">-</span><span class="token constant">TOKEN</span></code> 请求头。你可以将令牌保存在 HTML <code class=" language-php">meta</code> 标签中:</p><pre class=" language-php"><code class=" language-php"><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>csrf-token<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ csrf_token() }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span></code></pre><p>一旦创建了 <code class=" language-php">meta</code> 标签,你就可以使用类似 jQuery 的库将令牌自动添加到所有请求的头信息中。这可以为您基于 AJAX 的应用提供简单、方便的 CSRF 保护。</p><pre class=" language-php"><code class=" language-php">$<span class="token punctuation">.</span><span class="token function">ajaxSetup<span class="token punctuation">(</span></span><span class="token punctuation">{</span>
headers<span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">'X-CSRF-TOKEN'</span><span class="token punctuation">:</span> $<span class="token punctuation">(</span><span class="token string">'meta[name="csrf-token"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">attr<span class="token punctuation">(</span></span><span class="token string">'content'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="csrf-x-xsrf-token"></a></p><h2><a href="#csrf-x-xsrf-token">X-XSRF-TOKEN</a></h2><p>Laravel 将当前的 CSRF 令牌存储在由框架生成的每个响应中包含的一个<code class=" language-php"><span class="token constant">XSRF</span><span class="token operator">-</span><span class="token constant">TOKEN</span></code> cookie 中。你可以使用该令牌的值来设置 X-XSRF-TOKEN 请求头信息。</p><p>这个 cookie 作为头信息发送主要是为了方便,因为一些 JavaScript 框架,如 Angular,会自动将其值添加到 <code class=" language-php">X<span class="token operator">-</span><span class="token constant">XSRF</span><span class="token operator">-</span><span class="token constant">TOKEN</span></code> 头中.</p><h2>译者署名</h2><table><thead><tr><th>用户名</th><th>头像</th><th>职能</th><th>签名</th></tr></thead><tbody><tr><td><a href="http://weibo.com/wangkaibo">@王凯波</a></td><td><img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/1924_1487053084.jpeg?imageView2/1/w/100/h/100"></td><td>翻译</td><td>面向工资编程 <a href="https://github.com/wangkaibo/">@wangkaibo</a></td></tr></tbody></table></article>
- 入门指南
- 安装
- 配置信息
- 文件夹结构
- 请求周期
- 开发环境部署
- Valet
- Homestead
- 核心概念
- 服务提供者
- Facades
- Contracts
- 服务容器
- HTTP 层
- 路由
- 中间件
- CSRF 保护
- 控制器
- 请求
- 响应
- 视图
- Session
- 表单验证
- 前端
- Blade 模板
- 本地化
- 前端指南
- 编辑资源 Mix
- 安全
- API 认证
- 用户认证
- 用户授权
- 加密解密
- 哈希
- 重置密码
- 数据库
- 快速入门
- 查询构造器
- 分页
- 数据库迁移
- Redis
- 数据填充
- Eloquent ORM
- Eloquent ORM快速入门
- 模型关联
- Eloquent 集合
- 修改器
- 序列化
- 综合话题
- Artisan 命令行
- 广播系统
- 缓存系统
- 集合
- 错误与日志
- 事件系统
- 文件存储
- 辅助函数
- 邮件发送
- 消息通知
- 扩展包开发
- 队列
- 任务调度