# 表單構建
更改之前創建好的注冊頁面 `resources/views/user/auth/create.blade.php`:
~~~~ html
@extends('_layout.default')
@section('title', '注冊')
@section('content')
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default mt-5">
<div class="panel-heading mb-3">
<h4>注冊</h4>
</div>
<div class="panel-body">
<form method="POST"
action="{{ url('save') }}">
<input type="hidden" name="__token__" value="{{ $token }}" />
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">用戶名</span>
</div>
<input type="text"
class="form-control"
name="name">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">郵箱</span>
</div>
<input type="email"
class="form-control"
name="email">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">密碼</span>
</div>
<input type="password"
class="form-control"
name="password">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">確認密碼</span>
</div>
<input type="password"
class="form-control"
name="password_confirm">
</div>
<button type="submit"
class="btn btn-primary btn-block">注冊</button>
</form>
</div>
</div>
</div>
@stop
~~~~
修改控制器代碼 `application/user/controller/Auth.php`:
~~~~ php
public function create()
{
$token = $this->request->token('__token__', 'sha1');
$this->assign('token', $token);
return $this->fetch();
}
~~~~
這一步的目的是將自定義 CSRF Token 傳入模板當中.
## CSRF 防御
> 跨站請求偽造(英語:Cross-site request forgery),也被稱為one-click attack 或者session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制用戶在當前已登錄的 Web 應用程序上執行非本意的操作的攻擊方法. https://zh.wikipedia.org/zh/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0
> 假如一家銀行用以運行轉賬操作的URL地址如下: `http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName`
那么,一個惡意攻擊者可以在另一個網站上放置如下代碼: `<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">`
如果有賬戶名為Alice的用戶訪問了惡意站點,而她之前剛訪問過銀行不久,登錄信息尚未過期,那么她就會損失1000資金.
這種惡意的網址可以有很多種形式,藏身于網頁中的許多地方.此外,攻擊者也不需要控制放置惡意網址的網站.例如他可以將這種地址藏在論壇,博客等任何用戶生成內容的網站中.這意味著如果服務端沒有合適的防御措施的話,用戶即使訪問熟悉的可信網站也有受攻擊的危險.
## 防御措施
* 添加校驗token
> 由于 `CSRF` 的本質在于攻擊者欺騙用戶去訪問自己設置的地址,所以如果要求在訪問敏感數據請求時,要求用戶瀏覽器提供不保存在 `cookie` 中,并且攻擊者無法偽造的數據作為校驗,那么攻擊者就無法再運行 `CSRF` 攻擊.這種數據通常是窗體中的一個數據項.服務器將其生成并附加在窗體中,其內容是一個偽隨機數.當客戶端通過窗體提交請求時,這個偽隨機數也一并提交上去以供校驗.正常的訪問時,客戶端瀏覽器能夠正確得到并傳回這個偽隨機數,而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽隨機數的值,服務端就會因為校驗 `token` 的值為空或者錯誤,拒絕這個可疑請求.
* 檢查 Referer 字段
> `HTTP` 頭中有一個 `Referer` 字段,這個字段用以標明請求來源于哪個地址.在處理敏感數據請求時,通常來說,`Referer` 字段應和請求的地址位于同一域名下.以上文銀行操作為例,`Referer` 字段地址通常應該是轉賬按鈕所在的網頁地址,應該也位于 `www.examplebank.com` 之下.而如果是 `CSRF` 攻擊傳來的請求,`Referer` 字段會是包含惡意網址的地址,不會位于 `www.examplebank.com` 之下,這時候服務器就能識別出惡意的訪問.
這種辦法簡單易行,工作量低,僅需要在關鍵訪問處增加一步校驗.但這種辦法也有其局限性,因其完全依賴瀏覽器發送正確的 `Referer` 字段.雖然 `http` 協議對此字段的內容有明確的規定,但并無法保證來訪的瀏覽器的具體實現,亦無法保證瀏覽器沒有安全漏洞影響到此字段.并且也存在攻擊者攻擊某些瀏覽器,篡改其 `Referer` 字段的可能.
上面這段代碼中的 `{:token()}` 是通過添加校驗 `token` 來防止 `CSRF` 攻擊.
- 第一章. 基礎信息
- 1.1 序言
- 1.2 關于作者
- 1.3 本書源碼
- 1.4 反饋糾錯
- 1.5 安全指南
- 1.6 捐助作者
- 第二章. 開發環境布置
- 2.1 編輯器選用
- 2.2 命令行工具
- 2.3 開發環境搭建
- 2.4 瀏覽器選擇
- 2.5 第一個應用
- 2.6 Git 工作流
- 第三章. 構建頁面
- 3.1 章節說明
- 3.2 靜態頁面
- 3.3 Think 命令
- 3.4 小結
- 第四章. 優化頁面
- 4.1 章節說明
- 4.2 樣式美化
- 4.3 局部視圖
- 4.4 路由鏈接
- 4.5 用戶注冊頁面
- 4.6 集中視圖
- 4.7 小結
- 第五章. 用戶模型
- 5.1 章節說明
- 5.2 數據庫遷移
- 5.3 查看數據表
- 5.4 模型文件
- 5.5 小結
- 第六章. 用戶注冊
- 6.1 章節說明
- 6.2 注冊表單
- 6.3 用戶數據驗證
- 6.4 注冊失敗錯誤信息
- 6.5 注冊成功
- 6.6 小結
- 第七章. 會話管理
- 7.1 章節說明
- 7.2 會話
- 7.3 用戶登錄
- 7.4 退出
- 7.5 小結
- 第八章. 用戶 CRUD
- 8.1 章節說明
- 8.2 重構代碼
- 8.3 更新用戶
- 8.4 權限系統
- 8.5 列出所有用戶
- 8.6 刪除用戶
- 8.7 訪客模式
- 8.8 優化前端
- 8.9 小結
- 第九章. 微博 CRUD
- 9.1 章節說明
- 9.2 微博模型
- 9.3 顯示微博
- 9.4 發布微博
- 9.5 微博數據流
- 9.6 刪除微博
- 9.7 小結