Laravel教我用新思路防范CSRF

用了半年的Laravel,越來越喜歡他了,他大量的設計都和我的觀念相互印證,而且往往更加精妙和通用。今天就提筆記一個關于CSRF防護的問題。

我以前的方案

在我之前設計和使用的系統中,為了避免有人不小心寫出CSRF漏洞,我會全局禁止$_REQUEST的使用以及混用POST和GET的行為,要求開發人員分清每個傳入數據是POST還是GET。

于是我會在Reqeust對象上增加get($field_name, $default), post($field_name, $default) 的方法。并且直接在框架代碼啟動的時候將全局變量$_REQUEST置為空數組。

Laravel的方案

Part 1 Global CSRF Protection

Laravel推薦在全局注冊VerifyCsrfToken的Middleware,對所有Post,Put,Delete請求自動校驗是否帶合法的_csrf token。而要在表單中添加這個Token,只需要在form中加一行:

 <?php echo csrf_field(); ?> 

獲取表單值的方法:

$request->input('name', 'default name');

Part 2 路由層面區分Post/Get

// 同個Path下的Get,Post請求會根據配置不同進入不同的處理邏輯
Route::get('/path', 'XXXController@func_get');
Route::post('/path', 'XXXController@func_post');

我覺得Laravel這么設計比我高明在兩個地方:

  1. 對于新人,如果在Laravel中新增了一個表單,Post發現提交的時候提示CSRF校驗失敗,他很容易知道有這么個校驗,且開發環境下可以友好的提示他如何搞定這個問題。
    而我的做法由于和PHP原生行為不一致,第一次碰到的人會很奇怪,就算花時間最終搞明白了,他也會覺得自己掉了個坑,因為我沒有任何提示。(其實現在想來是可以有提示的,應該將$_REQUEST改成一個每次調用都拋Exception給予提示的閉包)。

  2. Laravel可以方便的配置例外情況。本周即將發布的5.1-LTS版包涵一個我很期待的改進就是可以通過配置,忽略特定路徑下的CSRF校驗,以便兼容第三方代碼組件和第三方的Post數據回傳。詳見

依然可能有的問題

我之前的項目中,到后來,會發現有人寫這樣的代碼:

$val = $request->get('name', $request->post('name', 'defailt name'));

這么寫有時候是真的需要;但大多數時候只是因為懶/或者copy來的代碼自己也沒搞明白。

在Laravel中也無法完全避免這類問題,因為路由配置的時候除了Rouet::get() Route::post() 還有個大殺器 Route::any(),它同時兼容get和post請求,間接引入了同樣的問題。

遺憾

雖然在Laravel中,上述問題我可以增加UnitTest,檢查大家對any()的使用,但實在不夠優雅,誰有更好的思路,非常希望你能來信告訴我 icedfish@gmail.com

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容