PHP安全編碼

1、開始前的一些建議

1.不要相信任何用戶輸入或第三方數據來源,包括$_GET、$_POST($_FILES)、$_COOKIE$_SERVER的部分參數等。php

2.HTML、PHP、MYSQL等使用統一的UTF-8編碼。html

3.數據庫SQL構造時儘可能使用'包裹參數。mysql

4.參數對比時正確使用 === 和 == 。web

5.儘可能選擇白名單而非黑名單式過濾。sql

2、關於SQL注入

1.SQL注入的產生緣由

SQL注入的產生在於外界的輸入改變了本來定義的SQL語意,譬如:數據庫

本來定義的SQL語意,瀏覽器

$_GET['name'] = 'abc';安全

$name = $_GET['name'];服務器

SELECT * FROM `admin` where user_name = '$name';cookie

最終生成的SQL爲,SELECT * FROM `admin` where user_name = 'abc';

外界輸入改變後的語意,

$_GET['name'] = 'abc\' or \'a\'=\'a';

$name = $_GET['name'];

SELECT * FROM `admin` where user_name = '$name';

最終生成的SQL爲,SELECT * FROM `admin` where user_name = 'abc' or 'a'='a';

此時SQL的語意多加了原定以外的 or 'a'='a' ,因而注入產生。

2.SQL注入的防護

(1)使用PDO或mysqli預編譯處理SQL

使用預處理語句時,PHP請求MySQL將SQL進行預編譯,而後再發送參數,所以不管參數是何內容MySQL均將參數看成普通的字符串(或整型、浮點型)處理。

例如上一例子最終生成的SQL爲,SELECT * FROM `admin` where user_name = 'abc\' or \'a\'=\'a';

此時沒法發生SQL語意的改變,故能防止SQL注入。

注意:PDO兼容大部分數據庫,但須要PHP版本5.0+;mysqli只支持MySQL數據庫而且須要MySQL數據庫版本4.1.13+(服務端版本5.0.7+)。

(2)沒法使用PDO或mysqli的預編譯處理SQL時,使用addslashes而非mysql_real_escape_string做爲臨時安全過濾函數,對於參數類型爲整型時使用intval將變量轉換成整型。

使用addslashes能有效做爲安全過濾的前提條件是PHP請求數據庫時的字符集爲UTF-8參數位於 '' 內,其餘的諸如GBK等因其字符集的特殊性,部分特殊字符轉義後仍能造成 ' 從而繞過轉義。譬如:

在GBK字符集的環境下,0xbf27通過addslashes轉義後獲得0xbf5c27,數據庫將0xbf5c看成單字節字符而剩餘的27則被看成 ' 解析,故而依舊能形成SQL注入。

注 意:在舊版的PHP中(具體版本未知)mysql_real_escape_string是MySQL擴展中的函數,並不是PHP原有函數,此函數在調用時 先判斷是否已經鏈接上數據庫,這就意味着mysql_real_escape_string必須是鏈接數據庫以後才能使用,新版的PHP雖然調用時再也不需 要判斷是否已經鏈接上數據庫,但會拋出一個警告(mysql_real_escape_string(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead)。

 

3、關於XSS

1.XSS產生的緣由

正如《白帽子講web安全》中所說:XSS本質仍是一直「HTML注入」,用戶的數據被當成了HTML代碼的一部分來執行,從而混淆了本來語意,譬如:

原語意,

$_GET['page'] = 1;

$page = $_GET['page'];

<a href="http://www.xxx.com/?page=$page">xss</a>

最終生成 <a href="http://www.xxx.com/?page=1">xss</a>

外界輸入改變後的語意,

$_GET['page'] = '1" onlick="alert(1)">';

$page = $_GET['page'];

<a href="http://www.xxx.com/?page=$page">xss</a>

最終生成 <a href="http://www.xxx.com/?page=1" onclick="alert(1)">xss</a>

2.XSS的防護

(1)針對普通HTML的輸出,使用htmlspecialchars進行安全過濾。

(2)針對連接類型(如圖片、超鏈等)的輸出也可以使用htmlspecialchars進行安全過濾,但若是變量是整個URL則應檢查這個變量是否以http或https開頭,若是不是則自動補齊避免出現僞協議類的XSS攻擊。(例子:<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTs8L3NjcmlwdD4=">xss</a>)

注意:htmlentities只有使用ASCII或LATIN-1等HTML字符編碼時才須要使用,由於htmlentities會將不少安全的字符也轉換成HTML編碼。因爲htmlspecialchars並不會將 ' 轉換成HTML編碼,因此只有標籤屬性是以 "" 包裹變量而非 '' 時使用htmlspecialchars纔是安全的。

(3)針對富文本,採用白名單模式放行安全的標籤及屬性,再針對可能產生XSS的標籤和屬性作針對的安全過濾。

4、關於CSRF

1.CSRF產生的緣由

攻擊源以用戶的身份僞造請求,譬如:

a.com 站下存在着這樣的一個HTML標籤,<img src="http://b.com?action=del&id=1">

用戶請求a.com時將會產生一條請求 http://b.com?action=del&id=1 (假設這個請求的做用是刪除id爲1的一篇文章),瀏覽器會以用戶當前瀏覽器狀態在b.com的身份(主要爲cookie信息)請求http://b.com?action=del&id=1執行刪除id爲1的文章操做,這個操做並非用戶主觀操做而是攻擊源以用戶身份僞造的操做,而且這個請求是可以被攻擊源預知的。

2.CSRF的防護

(1)Anti CSRF token,對於敏感的操做(譬如增刪改以及敏感信息的查看)使用隨機的token進行驗證。

注意:Token必須足夠隨機,且Token驗證後應當即刪除。Token應儘可能放在表單中採用POST的方式提交避免Token泄露。

5、關於文件上傳

1.文件上傳漏洞產生的緣由

正常狀況下上傳文件是一個合理的功能,漏洞的產生在於用戶上傳了一個邏輯上並不容許上傳的文件類型,這個文件可以被Web容器解析而且用戶可以經過Web訪問。譬如:

$allowExt = array('image/jpeg','image/x-png','image/gif');

if(in_array($_FILES['file']['type'],$allowExt)){

    move_uploaded_file($_FILES['file']['tmp_name'],$_FILES['file']['name'])

}

2.文件上傳漏洞的防護

(1)容許上傳的文件類型應採用白名單方式,結合MIME Type和後綴檢查文件類型,上傳文件中$_FILES['file']['type']所示類型不可信。如上例,

$_FILES['file']['type']爲客戶端瀏覽器檢測所選上傳文件後提供,可是此參數可被人爲抓包修改,所以參數不可信。

(2)使用隨機文件名保存上傳的文件,避免因終止符形成的文件名中斷。如上例,

$_FILES['file']['name']爲xxx.php[\0].jpg時,對於低版本PHP(詳細版本未知)而言,PHP保存文件的過程當中遇到終止符[\0](0x00的16進制)時誤認爲文件名已結束,故最終保存在服務器的文件名將是xxx.php。

6、關於代碼執行漏洞

1.代碼執行漏洞的產生

危險函數執行了咱們原定計劃以外的代碼,而計劃以外的代碼可由用戶控制,譬如:

$_GET['test'] = 'phpinfo()'';

$test = $_GET['test'];

eval($test);

最終代碼等價:phpinfo();

2.代碼執行漏洞的防護

(1)可以執行PHP代碼的函數均有可能成爲危險函數,危險函數的輸入如爲用戶可控變量時使用白名單模式限制。

(2)使用 preg_replace_callback代替preg_replace/e模式而且嚴格控制正則匹配的內容是否可能產生不安全變量。

注意:eval是zend提供的函數而並不是PHP的原生函數,所以經過php.ini disable_functions沒法禁用(需經過第三方插件禁用)。

7、關於重放攻擊

1.重放攻擊的產生

攻擊源經過構造請求使目標服務器相信當前請求來源安全並正確響應請求。譬如:

一個修改原始密碼的連接,

http://www.abc.com/index.php?action=alterPassword&uid=123456&token=123

目標服務器僅驗證token是否有效,有效則容許修改uid爲123456的用戶密碼

2.重放攻擊的防護

(1)對請求的全部參數進行簽名防止參數被篡改,而且請求參數必須帶有當前請求的時間戳用於目標服務器判斷當前的請求是否過時。

源地址:https://www.mudoom.com/Article/show/classify_id/1/id/33.html  By佐柱

轉載請註明出處,也歡迎偶爾逛逛個人小站,謝謝 :)

相關文章
相關標籤/搜索