如何書寫安全的PHP代碼
PHP是一個很容易學習的語言, 許多人在沒有任何編程背景下學習它作為一種去增加一些互動元素到他們的網站的方法. 不幸的是,這往往意味著PHP程序員,尤其是那些較新的Web開發程序員, 并沒有覺察他們網站中潛在安全風險. 這里是一些比較常見的安全問題,以及如何去避免它們。
永遠,永遠信任你的用戶
不能說足夠的次數,你應該永遠,永遠, 信任你的用戶向你發送你期望的數據. 我聽到很多人回應,大概是"哦,沒有惡意的人將對我的網站感興趣"。這就錯了, 這里總是有懷有惡意的用戶可以利用一個安全漏洞,問題可以很容易被發現,因為一個用戶無意中做錯了。
因此, 所有網頁的發展的戒律,我不能再壓縮了的話就是:永遠,永遠,相信你的用戶。假定你的網站從使用者收集的每片數據含有惡意代碼,始終, 你認為已經檢查客戶端驗證的這些數據,例如在JavaScript ,如果你能夠達到這個目標,你應該有了一個良好的開端。如果PHP的安全性很重要,這一點就要重要地學習,個人來說,"PHP安全"是一個重大的問題。
全局變量
在許多語言,你必須明確地設定一個變量以使用它。 在PHP中,有一個選項" , register_globals" , 你可以在php.ini中設置,讓你可以使用全局變量,而不需要事先聲明。
考慮下面的代碼:
if ($password == "my_password") { $authorized = 1; } if ($authorized == 1) { echo "Lots of important stuff."; } |
許多人看上去覺得沒什么問題,而事實上,這方面的代碼在整個網站上應用. 但是,如果一個服務器開啟"register_globals"。然后,只需添加"?authorized=1"的URL將讓任何人都看到. 這是一個最普遍的PHP的安全問題。
所幸的是,這有兩個簡單的解決辦法. 第一,也許最好的,就是把"register_globals"關閉. 二是你必須明確只有你使用變量. 在上面的例子中,這將意味著加入"?authorized=0"; 在腳本的開始:
$authorized = 0; if ($authorized == 1) { |
錯誤信息
錯誤信息是一個非常有用的工具,無論是程序員和黑客. 開發者需要它們去改正錯誤. 黑客可以利用它們來找出一個網站的各種信息, 從目錄結構的服務器,數據庫登錄信息. 如果可能的話,最好是關閉所有的錯誤報告. PHP可以完成這項工作. htaccess或php.ini,設置"error_reporting" 的值改為"0" . 如果你有一個開發環境,您可以設定不同的錯誤報告級別。
#p#
SQL注入
PHP的一個最大優點就是,它可以方便地與數據庫中操作,最顯著的MySQL的. 很多人使用這個數據庫。不少網站,包括這一個,依賴于數據庫的函數. 然而,正如你所料,有這么大的權力你就要夠面對龐大的潛在安全問題. 所幸的是,有很多解決辦法. 最常見面安全問題是一個數據庫 SQL注入-當用戶利用一個安全故障在你的數據庫運行SQL語句. 讓我們用一個常見的例子. 許多登錄系統具有以下特點:一條線,看起來象不像是在檢查從表單輸入的用戶名和密碼, 比如去控制訪問一個管理員區:
$check = mysql_query("Select Username, Password, UserLevel FROM Users Where Username |
看上去很眼熟? 就表面看來,它好像做得不錯.上述并不像可以做許多破壞. 但話又說回來,我在"username" 輸入框輸入這樣的值并提交:
'' 或者 1=1 #
這個執行語句現在是這個樣子:
elect Username, Password FROM Users Where Username = '' or 1=1 #' and Password = ''; |
散列符號(#)告訴MySQL的它之后一切,都會被忽略. 所以實際上只是執行的SQL到這一點. 1永遠等于1 ,所以SQL將從數據庫返回所有的用戶名和密碼. 在大多數用戶登錄數據庫的首個戶名和密碼組合都是管理員用戶, 他干脆輸入了幾個符號作為管理員已登錄你的網站, 果他們其實都知道的用戶名和密碼,他們會有同樣的權力如。
一個小創意,上述情況可以進一步發揮,讓用戶建立自己的登錄帳號, 閱讀信用卡號碼,甚至刪除數據庫。
所幸的是,這種情況還是很容易避免. 通過檢查要進入數據庫的數據,并刪除或取消它們, 我們可以防止任何人在這個數據庫上執行他們自己的SQL語句. 函數的方法如下:
function make_safe($variable) { |
現在,修改了我們的執行語句.用_POST取代上面的執行變量, 我們現在把所有的用戶數據通過make_safe函數,在以下代碼:
$username = make_safe($_POST['username']); |
現在,如果一個用戶輸入惡意的上述數據,查詢看上去像下面這樣,是完全無害. 以下查詢將選擇從數據庫中的用戶都和"\' or 1=1 #"相等的。
Select Username, Password, UserLevel FROM Users Where Username |
現在,除非你曾經提供了一個非常特殊的用戶名和空白密碼, 你的惡意攻擊者將不能做任何損害的事. 像這樣檢查所有的數據通過你的數據庫是非常重要的,盡管你認為這是已經很安全. HTTP頭可以由用戶偽造. 他們參照地址可以偽造.瀏覽器用戶字符串可以偽造. 不要信任一條用戶發送的數據,雖然,你認為是安全的。
文件操作
一些現今的網站的URL,是這個樣子的:
index.php?page=contactus.html |
"index.php"文件包括"contactus.html"文件,而且這個網站似乎正常運行. 不過,用戶可以很容易地將"contactus.html"改成他們自己喜的東西. 舉例來說, 如果您正在使用Apache的mod_auth去保護文件,并儲存你的密碼在一個文件名為".htpasswd"(傳統姓名)里 ,然后,如果用戶訪問以下地址, 腳本將輸出你的用戶名和密碼:
index.php?page=.htpasswd |
通過改變URL,在某些系統中, 在另一個可以運行PHP的服務器去引用文件。害怕? 你應該害怕. 再次所幸的是,這是比較容易防范. 首先,你必須確保正確設置" open_basedir"在你的php.ini文件,并已設置"allow_url_fopen "為"Off" . 這將阻止大多數這類型的攻擊,以保護遠程文件和文件系統. 其次,如果可以的話,請檢查文件要求對有效文件. 如果你限制了某些文件可以用這個腳本, 你可以節省不少后來惡果。
使用默認
當mysql是安裝,它使用了默認用戶的"root"和空白的密碼. SQL Server的用途"sa"作為默認的用戶和提供了一個空白的密碼. 如果有人發現你的數據庫服務器地址,并想嘗試登錄, 這些都是首次組合,他們會嘗試. 如果你沒有設定不同的密碼(最好也和用戶, 那么你很可能一天一覺醒來發現你的數據庫已經被刪除,所有用戶號碼被盜. 和所有軟件一樣,你如果使用的軟件是默認用戶名和密碼,改變他們。
不要讓安裝文件在線
很多PHP項目用安裝文件來安裝. 其中有不少是一旦運行就自我刪除的,但許多不是這樣的,直到您刪除安裝文件. 如果讓安裝文件在線請注,他們可能仍然可用, 有人可以用它來復蓋你的整個網站。
預見性
試想一下,你的網站讓一個壞人盯上. 這個壞的人要打破你的管理區, 改變你的所有產品的描述如"這個產品很差勁" . 我猜測,他們首先會去http://www.yoursite.com/admin/ -萬一它存在. 將你的敏感文件和文件夾像預測一樣,他們很容易就受到黑客攻擊。
為此,要確保你的姓名你的敏感文件和文件夾,讓他們很難猜測. 把你的 admin 位于http://www.yoursite.com/jsfh8sfsifuhsi8392/ 或者更難去寫的,但它為你的網站添加一些額外的保障.如果你需要一個記得快的地址, 但不用"admin"或"administration" (或你的用戶名和密碼) . 用一些不經常用的。
這同樣適用于用戶名和密碼. 如果你有管理區,不要使用" admin "作為用戶名和" password "作為密碼. 針對一些特殊的情況,最好是兩個字母和數字(有的黑客利用一些所謂的"詞典攻擊" , 嘗試每一個字,在字典里的密碼,直到他們找到密碼。添加一對密碼,使這一類攻擊無用) . 這也是明智的去定期改變你的密碼 (每兩個月). 最后,要確保當一個用戶名輸入" Wrong Password " 當錯誤的密碼輸入時你的錯誤訊息給沒有輸出.如: " Unknown Username ",惡意用戶都知道,他們已經成功地猜測一個有效的用戶名. 對上述兩種手段,采用通用的"登錄錯誤"的錯誤信息 ,如果是用戶名和密碼輸入錯誤的惡意用戶就沒有任何辦法設想正確的用戶和密碼。
最后,徹底和完全地設想
你假設你的網站不會受到攻擊,或面要對任何問題的話,但當最終出事,你將有大量的麻煩. 如果,在另一方面, 假設你的每一個客人到你的網站是為了攻擊你,你永遠處于戰爭狀態, 你就能幫助你把你的網站做得安全,并準備得沒有一點閃失。
【編輯推薦】