在開發過程當中,除了確保業務邏輯沒有安全隱患外,應該充分了解和利用框架內建的安全機制或者工具來確保應用以及服務器的安全性,下面咱們總結下ThinkPHP中涉及到的安全機制。
php
系統安全指ThinkPHP能夠配合的服務器的安所有署策略。html
首先,咱們建議在條件允 許的狀況下,把框架目錄和項目目錄都部署在非WEB訪問目錄下面,ThinkPHP的訪問機制徹底支持框架和項目的非WEB目錄訪問,你只須要把入口文件 和資源(主要是指JS、樣式和圖片文件)目錄放置於WEB目錄下面便可。所以,建議的部署目錄以下:thinkphp
index.php 項目入口文件
數組
Public/ 項目資源文件目錄
緩存
Js/ JS目錄
安全
Css/ 樣式文件目錄
服務器
Images/ 圖像文件目錄
框架
protected/ (受保護的目錄,能夠部署到非WEB目錄或者設置安全訪問)
xss
ThinkPHP/ 框架系統目錄
函數
App/ 項目目錄
Uploads/ 項目上傳目錄
複製代碼
若是你已經經過部署策略設置了系統目錄安全訪問的話,則能夠跳過這段。
若是你沒法徹底作到上述的服務器目錄安全保護,也無需擔憂,ThinkPHP仍然能夠經過設置確保你的目錄安全。框架的核心文件自己已經作了訪問判斷,全部核心文件均不能直接在URL中被訪問,所以也不用擔憂直接訪問某些文件致使的錯誤暴露你的服務器路徑之類的信息。
對於應用目錄,系統則提供了目錄安全訪問機制,你能夠在第一次生成項目目錄結構以前,在入口文件中添加:
define('BUILD_DIR_SECURE', true);
複製代碼
運行項目後會自動給項目的相關目錄生成目錄安全文件(在相關的目錄下面生成空白的htm文件),而且能夠自定義安全文件的文件名 DIR_SECURE_FILENAME ,默認是index.html,若是你想給大家的安全文件定義爲default.html可使用
define('DIR_SECURE_FILENAME', 'default.html');
複製代碼
define('DIR_SECURE_FILENAME', 'index.html,index.htm');
複製代碼
默認的安全文件只是寫入一個空白字符串,若是須要寫入其餘內容,能夠經過DIR_SECURE_CONTENT參數來指定,例如:
define('DIR_SECURE_CONTENT', 'deney Access!');
複製代碼
下面是一個完整的使用目錄安全寫入的例子
define('BUILD_DIR_SECURE',true);
define('DIR_SECURE_FILENAME', 'index.html');
define('DIR_SECURE_CONTENT', 'deney Access!');
複製代碼
除 了目錄安全以外,還須要保護模板文件不被直接訪問,由於有可能會在模板文件中暴露數據表的字段信息。解決辦法是配置.htaccess文件(針對 Apache服務器,其餘服務器參考修改),把如下代碼保存在項目的模板目錄目錄(默認是Tpl)下保存存爲.htaccess。
<Files *.html>
Order Allow,Deny
Deny from all
</Files>
複製代碼
若是你的模板文件後綴不是html能夠將*.html改爲你的模板文件的後綴。
ThinkPHP內置的自動驗證和自動完成功能能夠有效地對錶單提交的數據安全加以控制。這兩部分在快速入門系列中已經有過詳細的介紹,就再也不描述了。
ThinkPHP內置了表單令牌驗證功能,能夠有效防止表單的重複提交等安全防禦。
表單令牌驗證相關的配置參數有:
'TOKEN_ON'=>true, // 是否開啓令牌驗證 默認關閉
'TOKEN_NAME'=>'__hash__', // 令牌驗證的表單隱藏字段名稱
'TOKEN_TYPE'=>'md5', //令牌哈希驗證規則 默認爲MD5
'TOKEN_RESET'=>true, //令牌驗證出錯後是否重置令牌 默認爲true
複製代碼
若是開啓表單令牌驗證功能,系統會自動在帶有表單的模板文件裏面自動生成以TOKEN_NAME爲名稱的隱藏域,其值則是TOKEN_TYPE方式生成的哈希字符串,用於實現表單的自動令牌驗證。
自動生成的隱藏域位於表單Form結束標誌以前,若是但願本身控制隱藏域的位置,能夠手動在表單頁面添加{__TOKEN__} 標識,系統會在輸出模板的時候自動替換。
若是頁面中存在多個表單,建議添加{__TOKEN__}標識,並確保只有一個表單須要令牌驗證。
若是個別頁面輸出不但願進行表單令牌驗證,能夠在控制器中的輸出方法以前動態關閉表單令牌驗證,例如:
C('TOKEN_ON',false);
$this->display();
複製代碼
$User = M("User"); // 實例化User對象
// 手動進行令牌驗證
if (!$User->autoCheckToken($_POST)){
// 令牌驗證錯誤
}
複製代碼
表單合法性檢測是3.1版本開始增長的表單提交字段檢測機制,你再也不須要擔憂用戶在提交表單的時候注入非法字段數據了。表單字段合法性檢測須要使用create方法建立數據對象的時候才能生效,有兩種方式:
能夠給模型配置insertFields 和 updateFields屬性用於新增和編輯表單設置,使用create方法建立數據對象的時候,不在定義範圍內的屬性將直接丟棄,避免表單提交非法數據。
insertFields 和 updateFields屬性的設置採用字符串(逗號分割多個字段)或者數組的方式,例如:
class UserModel extends Model{
protected $insertFields = array('account','password','nickname','email');
protected $updateFields = array('nickname','email');
}
複製代碼
設置的字段應該是實際的數據表字段,而不受字段映射的影響。
在使用的時候,咱們調用create方法的時候,會根據提交類型自動識別insertFields和updateFields屬性:
D('User')->create();
複製代碼
class UserModel extends Model{
protected $insertFields = 'account,password,nickname,email';
protected $updateFields = 'nickname,email';
}
複製代碼
若是不想定義insertFields和updateFields屬性,或者但願能夠動態調用,能夠在調用create方法以前直接調用field方法,例如,實現和上面的例子一樣的做用:
在新增用戶數據的時候,使用:
$User = M('User');
$User->field('account,password,nickname,email')->create();
$User->add();
複製代碼
而在更新用戶數據的時候,使用:
$User = M('User');
$User->field('nickname,email')->create();
$User->where($map)->save();
複製代碼
$User->field('status,create_time',true)->create();
複製代碼
對全局系統變量的獲取建議採用系統提供的變量獲取方法獲取,具體能夠參考快速入門系列的變量
若是你習慣於直接調用$_GET $_POST變量的話,那麼或者能夠採用ThinkPHP系統內置的對全局變量的安全過濾方式,只須要設置VAR_FILTERS參數。
例如:
'VAR_FILTERS'=>'htmlspecialchars'
複製代碼
在3.1.2版本開始,安全過濾方法的定義函數須要調整爲引用返回的方式,並且可以實現多維數組的遞歸過濾,例如:
'VAR_FILTERS'=>'filter_vars'
複製代碼
function filter_vars(&$value){
$value = htmlspecialchars($value);
}
複製代碼
對於WEB應用來講,SQL注入攻擊無疑是首要防範的安全問題,系統底層對於數據安全方面自己進行了不少的處理和相應的防範機制,例如:
$User = M("User"); // 實例化User對象
$User->find($_GET["id"]);
複製代碼
即使用戶輸入了一些惡意的id參數,系統也會強制轉換成整型,避免惡意注入。這是由於,系統會對數據進行強制的數據類型檢測,而且對數據來源進行數據格式轉換。並且,對於字符串類型的數據,ThinkPHP都會進行escape_string處理。
一般的安全隱患在於你的查詢條件使用了字符串參數,而後其中一些變量又依賴由客戶端的用戶輸入,要有效的防止SQL注入問題,咱們建議:
查詢條件儘可能使用數組方式,這是更爲安全的方式;
若是不得已必須使用字符串查詢條件,使用預處理機制;
where方法使用字符串條件的時候,支持預處理(安全過濾),並支持兩種方式傳入預處理參數,例如:
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
複製代碼
或者
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
複製代碼
$model->query('select * from user where id=%d and status=%d',$id,$status);
複製代碼
或者
$model->query('select * from user where id=%d and status=%d',array($id,$status));
複製代碼
execute方法用法同query方法。
XSS(跨站腳本攻擊)能夠用於竊取其餘用戶的Cookie信息,要避免此類問題,能夠採用以下解決方案:
直接過濾全部的JavaScript腳本;
轉義Html元字符,使用htmlentities、htmlspecialchars等函數;
系統的擴展函數庫提供了XSS安全過濾的remove_xss方法;
新版對URL訪問的一些系統變量已經作了XSS處理。
網站的上傳功能也是一個很是容易被攻擊的入口,因此對上傳功能的安全檢查是尤爲必要的。
系統提供的上傳擴展類庫(ORG.Net.UploadFile)提供了安全方面的支持,包括對文件後綴、文件類型、文件大小以及上傳圖片文件的合法性檢查,確保你已經在上傳操做中啓用了這些合法性檢查。
下面的一些安全建議也是很是重要的:對全部公共的操做方法作必要的安全檢查,防止用戶經過URL直接調用;不要緩存須要用戶認證的頁面;對於關鍵操做須要檢查用戶權限;對用戶的上傳文件,作必要的安全檢查,例如上傳路徑和非法格式。如非必要,不要開啓服務器的目錄瀏覽權限;對於項目進行充分的測試,不要生成業務邏輯的安全隱患(這多是最大的安全問題);