注:TP版本為3.1.3
在ThinkPHP框架下,兩次提交同一個表單,比如提交信息后在瀏覽器點擊后退退回上次的頁面,重新點擊提交按鈕,就會提示“表單令牌錯誤”的信息。
ThinkPHP新版內置了表單令牌驗證功能,可以有效防止表單的遠程提交等安全防護。
表單令牌驗證相關的配置參數有:
'TOKEN_ON'=>true, // 是否開啟令牌驗證
'TOKEN_NAME'=>'__hash__', // 令牌驗證的表單隱藏字段名稱
'TOKEN_TYPE'=>'md5', //令牌哈希驗證規則 默認為MD5
如果開啟表單令牌驗證功能,系統會自動在帶有表單的模板文件里面自動生成以TOKEN_NAME為名稱的隱藏域,其值則是TOKEN_TYPE方式生成的哈希字符串,用於實現表單的自動令牌驗證。
自 動生成的隱藏域位於表單Form結束標志之前,如果希望自己控制隱藏域的位置,可以手動在表單頁面添加{__TOKEN__} 標識,系統會在輸出模板的 時候自動替換。如果在開啟表單令牌驗證的情況下,個別表單不需要使用令牌驗證功能,可以在表單頁面添加{__NOTOKEN__},則系統會忽略當前表單 的令牌驗證。
如果頁面中存在多個表單,建議添加{__TOKEN__}標識,並確保只有一個表單需要令牌驗證。
模型類在創建數據對象的同時會自動進行表單令牌驗證操作,如果你沒有使用create方法創建數據對象的話,則需要手動調用模型的autoCheckToken方法進行表單令牌驗證。如果返回false,則表示表單令牌驗證錯誤。例如:
$User = M("User"); // 實例化User對象 // 手動進行令牌驗證 if (!$User->autoCheckToken($_POST)){ // 令牌驗證錯誤 }
下面看一下它是怎么生成的,如果你開啟了表單令牌。
文件目錄:/ThinkPHP/Lib/Core/Model.class.php
// 自動表單令牌驗證 // TODO ajax無刷新多次提交暫不能滿足 public function autoCheckToken($data) { // 支持使用token(false) 關閉令牌驗證 if(isset($this->options['token']) && !$this->options['token']) return true; if(C('TOKEN_ON')){ $name = C('TOKEN_NAME'); if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌數據無效 return false; } // 令牌驗證 list($key,$value) = explode('_',$data[$name]); if($value && $_SESSION[$name][$key] === $value) { // 防止重復提交 unset($_SESSION[$name][$key]); // 驗證完成銷毀session return true; } // 開啟TOKEN重置 if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]); return false; } return true; }
表單令牌是由下面的代碼生成的:
private function buildFormToken() { // 開啟表單驗證自動生成表單令牌 $tokenName = C('TOKEN_NAME'); $tokenType = C('TOKEN_TYPE'); $tokenValue = $tokenType(microtime(TRUE)); $token = '<input type="hidden" name="'.$tokenName.'" value="'.$tokenValue.'" />'; $_SESSION[$tokenName] = $tokenValue; return $token; }
所以表單令牌使用起來非常方便,只需要配置好,同時在控制器內驗證即可。