PHP網站建設中常見的安全威脅包括:SQL 注入、操縱 GET 和 POST 變量、緩衝區溢出攻擊、跨站點腳本攻擊、瀏覽器內的數據操縱和遠程表單提交。php
在 SQL 注入攻擊 中,用戶經過操縱表單或 GET 查詢字符串,將信息添加到數據庫查詢中。html
例如,假設有一個簡單的登陸數據庫。這個數據庫中的每一個記錄都有一個用戶名字段和一個密碼字段。構建一個登陸表單,讓用戶可以登陸。前端
解決這個問題的辦法是,將 PHP 的內置 mysql_real_escape_string() 函數用做任何用戶輸入的包裝器。mysql
這個函數對字符串中的字符進行轉義,使字符串不可能傳遞撇號等特殊字符並讓 MySQL 根據特殊字符進行操做。清單 7 展現了帶轉義處理的代碼。正則表達式
用戶擁有有效的密碼,並不意味着他將按照規則行事 —— 他有不少機會可以形成損害。例如,應用程序可能容許用戶查看特殊的內容。sql
好比 template.php?pid=33 或 template.php?pid=321。URL 中問號後面的部分稱爲查詢字符串。由於查詢字符串直接放在 URL 中,因此也稱爲 GET 查詢字符串。數據庫
這裏有什麼錯嗎?後端
首先,這裏隱含地相信來自瀏覽器的 GET 變量 pid 是安全的。瀏覽器
這會怎麼樣呢?安全
大多數用戶沒那麼聰明,沒法構造出語義攻擊。可是,若是他們注意到瀏覽器的 URL 位置域中的 pid=33,就可能開始搗亂。
若是他們輸入另外一個數字,那麼可能沒問題;可是若是輸入別的東西,好比輸入 SQL 命令或某個文件的名稱(好比 /etc/passwd),或者搞別的惡做劇,好比輸入長達 3,000 個字符的數值,那麼會發生什麼呢?
在這種狀況下,要記住基本規則,不要信任用戶輸入。
應用程序開發人員知道 template.php 接受的我的標識符(PID)應該是數字,因此可使用 PHP 的 is_numeric() 函數確保不接受非數字的 PID。
須要作的只是使用 strlen() 檢查變量的長度是否非零;若是是,就使用一個全數字正則表達式來確保數據元素是有效的。若是 PID 包含字母、斜線、點號或任何與十六進制類似的內容,那麼這個例程捕獲它並將頁面從用戶活動中屏蔽。
緩衝區溢出攻擊 試圖使 PHP 應用程序中(或者更精確地說,在 Apache 或底層操做系統中)的內存分配緩衝區發生溢出。
請記住,您多是使用 PHP 這樣的高級語言來編寫 Web 應用程序,可是最終仍是要調用 C(在 Apache 的狀況下)。與大多數低級語言同樣,C 對於內存分配有嚴格的規則。
緩衝區溢出攻擊向緩衝區發送大量數據,使部分數據溢出到相鄰的內存緩衝區,從而破壞緩衝區或者重寫邏輯。這樣就可以形成拒絕服務、破壞數據或者在遠程服務器上執行惡意代碼。
防止緩衝區溢出攻擊的唯一方法是檢查全部用戶輸入的長度。
注意,緩衝區溢出攻擊並不限於長的數字串或字母串。也可能會看到長的十六進制字符串(每每看起來像 \xA3 或 \xFF)。
記住,任何緩衝區溢出攻擊的目的都是淹沒特定的緩衝區,並將惡意代碼或指令放到下一個緩衝區中,從而破壞數據或執行惡意代碼。
對付十六進制緩衝區溢出最簡單的方法也是不容許輸入超過特定的長度。
若是您處理的是容許在數據庫中輸入較長條目的表單文本區,那麼沒法在客戶端輕鬆地限制數據的長度。在數據到達 PHP 以後,可使用正則表達式清除任何像十六進制的字符串。
在跨站點腳本(XSS)攻擊中,每每有一個惡意用戶在表單中(或經過其餘用戶輸入方式)輸入信息,這些輸入將惡意的客戶端標記插入過程或數據庫中。
例如,假設站點上有一個簡單的來客登記簿程序,讓訪問者可以留下姓名、電子郵件地址和簡短的消息。
惡意用戶能夠利用這個機會插入簡短消息以外的東西,好比對於其餘用戶不合適的圖片或將用戶重定向到另外一個站點的 JavaScript,或者竊取 cookie 信息。
幸運的是,PHP 提供了 strip_tags() 函數,這個函數能夠清除任何包圍在 HTML 標記中的內容。strip_tags() 函數還容許提供容許標記的列表。
從安全的角度來看,對公共用戶輸入使用 strip_tags() 是必要的。若是表單在受保護區域(好比內容管理系統)中,並且您相信用戶會正確地執行他們的任務(好比爲 Web 站點建立 HTML 內容),那麼使用 strip_tags() 多是沒必要要的,會影響工做效率。
還有一個問題:若是要接受用戶輸入,好比對貼子的評論或來客登記項,並須要將這個輸入向其餘用戶顯示,那麼必定要將響應放在 PHP 的 htmlspecialchars() 函數中。
這個函數將與符號、< 和 > 符號轉換爲 HTML 實體。例如,與符號(&)變成 &。這樣的話,即便惡意內容躲開了前端 strip_tags() 的處理,也會在後端被 htmlspecialchars() 處理掉。
有一類瀏覽器插件容許用戶篡改頁面上的頭部元素和表單元素。使用 Tamper Data(一個 Mozilla 插件),能夠很容易地操縱包含許多隱藏文本字段的簡單表單,從而向 PHP 和 MySQL 發送指令。
用戶在點擊表單上的 Submit 以前,他能夠啓動 Tamper Data。在提交表單時,他會看到表單數據字段的列表。
Tamper Data 容許用戶篡改這些數據,而後瀏覽器完成表單提交。
要防護這種工具,最簡單的方法是假設任何用戶均可能使用 Tamper Data(或相似的工具)。
只提供系統處理表單所需的最少許的信息,並把表單提交給一些專用的邏輯。例如,註冊表單應該只提交給註冊邏輯。
若是已經創建了一個通用表單處理函數,有許多頁面都使用這個通用邏輯,那該怎麼辦?
若是使用隱藏變量來控制流向,那該怎麼辦?
例如,可能在隱藏表單變量中指定寫哪一個數據庫表或使用哪一個文件存儲庫。有 4 種選擇:
不改變任何東西,暗自祈禱系統上沒有任何惡意用戶。
重寫功能,使用更安全的專用表單處理函數,避免使用隱藏表單變量。
使用 md5() 或其餘加密機制對隱藏表單變量中的表名或其餘敏感信息進行加密。在 PHP 端不要忘記對它們進行解密。
經過使用縮寫或暱稱讓值的含義模糊,在 PHP 表單處理函數中再對這些值進行轉換。例如,若是要引用 users 表,能夠用 u 或任意字符串(好比 u8y90×0jkL)來引用它。
後兩個選項並不完美,可是與讓用戶輕鬆地猜出中間件邏輯或數據模型相比,它們要好得多了。
Web 的好處是能夠分享信息和服務。壞處也是能夠分享信息和服務,由於有些人作事毫無顧忌。
以表單爲例。任何人都可以訪問一個 Web 站點,並使用瀏覽器上的 File > Save As 創建表單的本地副本。而後,他能夠修改 action 參數來指向一個徹底限定的 URL(不指向 formHandler.php,而是指向http://www.yoursite.com/formHandler.php,由於表單在這個站點上),作他但願的任何修改,點擊 Submit,服務器會把這個表單數據做爲合法通訊流接收。
首先可能考慮檢查 $_SERVER['HTTP_REFERER'],從而判斷請求是否來自本身的服務器,這種方法能夠擋住大多數惡意用戶,可是擋不住最高明的黑客。這些人足夠聰明,可以篡改頭部中的引用者信息,使表單的遠程副本看起來像是從您的服務器提交的。
處理遠程表單提交更好的方式是,根據一個唯一的字符串或時間戳生成一個令牌,並將這個令牌放在會話變量和表單中。提交表單以後,檢查兩個令牌是否匹配。若是不匹配,就知道有人試圖從表單的遠程副本發送數據。
使用 mysql_real_escape_string() 防止 SQL 注入問題。
使用正則表達式和 strlen() 來確保 GET 數據未被篡改。
使用正則表達式和 strlen() 來確保用戶提交的數據不會使內存緩衝區溢出。
使用 strip_tags() 和 htmlspecialchars() 防止用戶提交可能有害的 HTML 標記。
避免系統被 Tamper Data 這樣的工具突破。
使用唯一的令牌防止用戶向服務器遠程提交表單。