王 欣
(呼倫貝爾學院網絡中心 內蒙古 海拉爾區 021008)
隨著互聯網的深入發展,各企事業單位的門戶網站已經成為了對外宣傳和提供信息服務的窗口。PHP因為其功能強大、入門學習簡單、代碼執行效率高等優點,成為了Web應用開發的流行語言。由于廣泛使用,且沒有像針對ASP網站那么多的入侵工具,所以網站開發者對PHP的后臺并不重視,大部分設計者在編寫網站代碼時,對頁面變量的過濾僅僅參照于 ASP,但這些變量大多數都不安全。所以利用PHP安全漏洞對Web網站進行攻擊的行為也越來越多,這給Web應用的安全帶來了嚴重的威脅。
呼倫貝爾地區據不完全統計有網站980余個,其中以PHP代碼編寫的網站數量約占30%。作者長期以來一直關注著本地區的 Web網站安全狀況,近期對區域內的PHP網站進行了一次安全漏洞掃描,根據掃描結果來進行分析,很多網站存在語義 URL、跨站請求偽造、跨站腳本、SQL注入、文件上傳等安全漏洞。本文將對呼倫貝爾地區PHP網站普遍存在的語義URL和SQL注入安全漏洞進行分析,并找出解決安全漏洞的方法。
語義 URL攻擊是利用URL特性進行的一種攻擊。URL是定位Internet資源的重要手段,在很多的應用中,常常可以見到利用 URL 來將參數傳遞到另一個程序。如果用戶出于某種目的而改變其中某些參數的值,這就產生了語義 URL 攻擊。
有關語義 URL 攻擊的一個典型例子是 Web應用中的密碼找回系統。在實際應用中,很多用戶登錄表單的旁邊常有一個“忘記密碼”的鏈接,當用戶忘記密碼時,可以點此鏈接進入到密碼找回系統界面。 密碼找回系統通過詢問用戶特定的問題并根據用戶的答案來判斷當前用戶是否是找回自己的密碼,如果是,則系統將提供一個表單讓用戶輸入一個Email地址,以便系統將密碼發送到此 Email 地址所在的郵箱。接受Email 地址的表單HTML代碼假設如下所示:

此表單含有一個隱藏域,用于存儲要找回密碼的用戶名。從上面的表單 HTML代碼可以看出,當用戶按下“提交”按鈕時,瀏覽器地址欄將出現以下信息:http://…/resetpass.php?user=Cheng&email=cmhman@yahoo.com.cn
用戶若對 Web 知識有所了解,其便會注意到上述 URL 是帶參數的。如果將上述 URL 中的user 參數的值改為其他人的用戶名,郵箱地址不變,那么該用戶就可以重置并獲得他人的密碼。
上述密碼找回系統中的語義 URL 攻擊,其發生的根本原因在于 resetpass.php 沒有對 URL 中提交的 user 參數值進行驗證,使得攻擊者有機可乘,非法重置并竊取他人密碼。為了防范上述密碼找回系統中的語義 URL 攻擊,必須對用戶身份(即 user 參數值)進行確認,采用 Session 跟蹤是一個比較好的方法,代碼如下:

在上述代碼中,$_SESSION['verified']是在用戶正確回答了問題后產生的,用它來和表單隱藏域中的參數值進行比較,便可知道此用戶是否是合法找回密碼的當前用戶而不是攻擊者。
Web 應用程序未對用戶輸入進行嚴格驗證和過濾, 致使攻擊者可以注入各種特殊字符串、SQL命令等,是導致網站受到 SQL 注入攻擊的根本原因。下面用一個實例來具體說明未對用戶輸入進行驗證是如何產生 SQL 注入攻擊的。假設某高校教務管理系統有一個學生成績查詢頁面,學號是查詢學生成績的關鍵字之一。一般情況下,學生的學號都是由數字組成的字符串,在查詢時,只要輸入合法的學生學號,就可以獲得該學號所對應學生的各門課成績。如果該教務管理系統在查詢學生成績時,采用的是通過輸入參數動態構造SQL 語句并提交數據庫執行的方法,那么,程序的實現代碼有可能為:

如果查詢者輸入的是合法的學號(如 123456 7890),那么提交給MySQL 數據庫(此處假定該教務系統后臺使用的是 MySQL 數據庫,其他數據庫的原理相同)執行的 SQL 語句最終為:select* from Grade where Sno='1234567890'
該語句是一個能夠返回學生成績的正常 SQL語句,自然不會出現什么問題。但是,若查詢者不輸入合法的學號,而是輸入如下參數:1234567890';
delete from Grade where Sno='1234567890'--,則最終提交給MySQL數據庫執行的 SQL 語句為:

從上述提交給數據庫執行的SQL語句可以看出,學號為 1234567890 的學生的成績將被刪除。由此可以看出,如果對用戶的輸入盲目信任而不加嚴格驗證的話,是可能發生SQL注入攻擊的。SQL 注入攻擊產生的根本原因是系統開發人員在開發Web應用系統時未對用戶的輸入進行嚴格的驗證。因此,針對 SQL用戶輸入的驗證,下面是行之有效的一些具體措施:
攻擊者進行SQL注入攻擊的常用手段一般是在系統接受用戶輸入的地方注入非法SQL指令并使數據庫系統執行,采用傳統方法動態構造 SQL語句的 Web系統常受此問題困擾。采用參數化的查詢手段可以在很大程度上對SQL注入攻擊進行有效避免。參數化查詢方法與傳統的動態構造SQL語句有很大的不同。參數化查詢不會將用戶的輸入作為SQL命令來執行,原因是:采取參數化查詢方法,數據庫系統在執行SQL語句時,會編譯事先設計好的SQL指令,然后再套用用戶的輸入參數,之后才由數據庫執行。這樣一來,即便攻擊者輸入的不是合法參數而是惡意SQL命令,其也不會得到執行,而只能作為參數處理,因為此時SQL語句中的命令部分已經編譯完畢,不會對用戶輸入的惡意 SQL命令再進行編譯了。通過這樣的機制,絕大部分的SQL注入攻擊都可以得到有效的防范。下面以MySQL數據庫為例,看看參數化查詢的一種具體實現方法:

使用參數化查詢方法,可能會對程序的維護及某些功能的實現帶來不便,但是,這與不使用參數化查詢,系統可能遭受SQL注入攻擊相比,些許的不便還是值得的,畢竟作為一個面對各種類型客戶的Web系統來說,安全是十分重要的。
從SQL注入攻擊產生的原因可知,對用戶輸入進行嚴格驗證,也是行之有效的防范SQL注入攻擊的手段。對用戶輸入進行驗證的方法有很多種,要根據具體情況進行選擇。總的說來,有如下一些方法:
1.對用戶輸入數據的類型進行驗證
在Web應用程序中,變量的類型大致可以分為三種:數字型、日期時間型、字符串型。因此,用戶輸入的數據類型一般情況下也不外乎以上三種。對要求數字型和日期時間型的用戶輸入進行驗證是比較方便的,因為開發Web應用程序的各種腳本語言幾乎都有相應的函數可以用來對這兩種變量值的類型進行判斷。比如,在PHP中,驗證用戶的輸入是否為數字型可以使用函數 is_integer()、is_double(),前者用于驗證用戶輸入是否為整數,后者用于驗證用戶輸入是否為浮點數;驗證用戶的輸入是否為有效的日期時間,可以使用函數checkdate()。對于前面在 SQL 注入產生原因的分析中所舉的例子,因為學號一般來說是由數字組成的字符串,因此,對輸入學號的驗證可以采用函數 is_integer()來進行,如果判斷下來,用戶輸入的是一個整數,那么就可以認為其輸入的是合法學號。
如果 Web 應用程序要求用戶輸入的不是數字類型參數,也不是日期時間類型參數,而是可能由各種字符組成的一般字符串,那就不能采用判斷數據類型的方法來驗證用戶的輸入了,而這種情況恰恰又是 Web 應用中最常見的。下面研究當輸入為一般字符串時的驗證方法。
2.利用正則表達式對用戶的輸入進行驗證
在一般情況下,對于大多數Web應用程序來說,用戶的輸入不管是在外在形式還是在內在屬性上,都是有一定規律可循的,比如,如果在用戶注冊及登錄時要求輸入郵箱信息,由于郵箱具有特定的格式:用戶名@域名,我們就可以構造一個正則表達式對用戶的輸入進行驗證。使用正則表達式除可以對用戶的輸入進行驗證之外, 還可以規范化用戶的輸入,而規范化用戶的輸入對于防范未知的 SQL 注入攻擊形式是及其有效的。
3.對用戶輸入的長度進行驗證
眾多的實踐表明,對用戶輸入長度進行驗證對于防范SQL注入攻擊特別是對于編解碼字符串形式的SQL注入攻擊是十分有效的。利用正則表達式規范化用戶的輸入不能防范編解碼形式的SQL注入攻擊,例如:若正則表達式規定用戶在輸入字符串中不能包含單引號,但用戶如果將單引號進行編碼后輸入,然后再解碼還原為單引號的本來形式,正則表達式就檢測不出來了。除了單引號外,對于其他的字符也可以用編解碼的形式逃過正則表達式的檢測。但是,輸入字符通過編碼以后,輸入的長度會增加,如果程序對用戶輸入的長度進行了規定,那么編碼后的字符串就不會被系統所接受,從而有效地防范了編解碼形式的SQL注入攻擊。
對于一個已經存在并正在使用的PHP網站來說,如果在原先的開發過程中沒有注意進行 SQL注入攻擊方面的防范,自然是十分危險的。但是,為了防范SQL注入攻擊而全面修改Web應用程序代碼,也顯得不太現實,付出的代價是難以承受的。在這種情況下,為了最大可能防范SQL注入攻擊,可以對數據庫及PHP配置文件進行適當設置。在數據庫方面的設置主要有禁止遠程連接數據庫、刪除多余用戶、目錄訪問權限限制、數據庫服務器權限控制、禁止多語句查詢等。PHP 配置文件的設置主要是打開 magic_quotes_gpc 選項和關閉錯誤信息的顯示, magic_quotes_gpc 選項打開以后,系統將對向數據庫提交的 SQL 查詢進行轉義,從而在相當程度上減少了 SQL 注入攻擊的發生。系統錯誤信息顯示關閉以后,程序運行出現錯誤時,就不會在客戶端瀏覽器顯示出具體的錯誤信息,這樣可以防止攻擊者進行錯誤查詢攻擊來獲得數據庫敏感信息。
通過對語義URL和SQL注入漏洞的分析,最終得出了解決這兩項PHP網站主要安全漏洞的方法。只要PHP網站開發人員和網站管理員提高網絡安全意識,在開發和管理網站的過程中采取適當的措施,大部分PHP安全漏洞還是可以防范的。