<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 命令行
- 廣播系統
- 緩存系統
- 集合
- 錯誤與日志
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度