程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP入門知識 >> PHP+MYSQL網站SQL Injection攻防

PHP+MYSQL網站SQL Injection攻防

編輯:PHP入門知識

程序員們寫代碼的時候講究TDD(測試驅動開發):在實現一個功能前,會先寫一個測試用例,然後再編寫代碼使之運行通過。其實當黑客SQL Injection時,同樣是一個TDD的過程:他們會先嘗試著讓程序報錯,然後一點一點的修正參數內容,當程序再次運行成功之時,注入也就隨之成功了。

進攻:

假設你的程序裡有類似下面內容的腳本:

$sql = "SELECT id, title, content FROM articles WHERE id = {$_GET['id']}";

正常訪問時其URL如下:

/articles.php?id=123

當黑客想判斷是否存在SQL Injection漏洞時,最常用的方式就是在整形ID後面加個單引號:

/articles.php?id=123'

由於我們沒有過濾$_GET['id']參數,所以必然會報錯,可能會是類似下面的信息:

supplied argument is not a valid MySQL result resource in ...

這些信息就足以說明腳本存在漏洞了,我們可以再耍點手段:

/articles.php?id=0 union select 1,2,3

之所以select 1,2,3是因為union要求兩邊的字段數一致,前面是id,title,content三個字段,後面1,2,3也是三個,所以不會報語法錯誤,還有設置id=0是一條不存在的記錄,那麼查詢的結果就是1,2,3,反映到網頁上,原本顯示id的地方會顯示1,顯示title的地方會顯示2,顯示content的地方會顯示3。

至於如何繼續利用,還要看magic_quotes_gpc的設置:

當magic_quotes_gpc為off時

/articles.php?id=0 union select 1,2,load_file('/etc/passwd')

如此一來,/etc/passwd文件的內容就會顯示在原本顯示content的地方。

當magic_quotes_gpc為on時

此時如果直接使用load_file('/etc/passwd')就無效了,因為單引號被轉義了,但是還有辦法:

/articles.php?id=0 union select 1,2,load_file(char(47,101,116,99,47,112,97,115,115,119,100))

其中的數字就是/etc/passwd字符串的ASCII:字符串每個字符循環輸出ord(...)

除此以為,還可以使用字符串的十六進制:字符串每個字符循環輸出dechex(ord(...))

/articles.php?id=0 union select 1,2,load_file(0x2f6574632f706173737764)

這裡僅僅說了數字型參數的幾種攻擊手段,屬於冰山一角,字符串型參數等攻擊手段看後面的文檔鏈接。

防守:

網絡上有一些類似SQL Injection Firewall的軟件可供使用,比如說GreenSQL,如果網站已經開始遭受SQL Injection攻擊,那麼使用這樣的快捷工具往往會救你一命,不過這樣的軟件在架構上屬於一個Proxy的角色,多半會影響網站並發性能,所以在選擇與否這個問題上最好視客觀條件來慎重決定。很多時候專業的軟件並不是必須的,還有很多輕量級解決方案,下面演示一下如何使用awk來檢測可能的漏洞。

創建detect_sql_injection.awk腳本,內容如下(如果要拷貝一下內容的話記得不要包括行號):

01 #!/bin/gawk -f
02
03 /\$_(GET|POST|COOKIE|REQUEST)\s*\[/ {
04     IGNORECASE = 1
05     if (match($0, /\$.*(sql|query)/)) {
06         IGNORECASE = 0
07         output()
08         next
09     }
10 }
11
12 function output()
13 {
14     $1 = $1
15     print "CRUD: " $0 "\nFILE: " FILENAME "\nLINE: " FNR "\n"
16 }


此腳本可匹配出類似如下的問題代碼,想要擴展匹配模式也容易,只要照貓畫虎寫if match語句即可。

1:$sql = "SELECT * FROM users WHERE username = '{$_POST['username']}'";
2:$res = mysql_query("SELECT * FROM users WHERE username = '{$_POST['username']}'");


使用前別忘了先chmod +x detect_sql_injection.awk,有兩種調用方法:

1:./detect_sql_injection.awk /path/to/php/script/file
2:find /path/to/php/script/directory -name "*.php" | xargs ./detect_sql_injection.awk


會把有問題的代碼信息顯示出來,樣子如下:

CRUD: $sql = "SELECT * FROM users WHERE username = '{$_POST['username']}'";
FILE: /path/to/file.php
LINE: 123


現實環境中有很多應用這個腳本的方法,比如說通過CRON定期掃描程序源文件,或者在SVN提交時通過鉤子方法自動匹配。

使用專業工具也好,檢測腳本亦罷,都是被動的防守,問題的根本始終取決於在程序員頭腦裡是否有必要的安全意識,下面是一些必須要牢記的准則:

1:數字型參數使用類似intval,floatval這樣的方法強制過濾。
2:字符串型參數使用類似mysql_real_escape_string這樣的方法強制過濾,而不是簡單的addslashes。
3:最好拋棄mysql_query這樣的拼接SQL查詢方式,盡可能使用PDO的prepare綁定方式。
4:使用rewrite技術隱藏真實腳本及參數的信息,通過rewrite正則也能過濾可疑的參數。
5:關閉錯誤提示,不給攻擊者提供敏感信息:display_errors=off。
6:以日志的方式記錄錯誤信息:log_errors=on和error_log=filename,定期排查,Web日志最好也查。
7:不要用具有FILE權限的賬號(比如root)連接MySQL,這樣就屏蔽了load_file等危險函數。
8:......

網站安全其實並不復雜,總結出來就是一句話:過濾輸入,轉義輸出。其中,我們上面一直討論的SQL Injection問題就屬於過濾輸入問題,至於轉義輸出問題,其代表是Cross-site scripting,但它不屬於本文的范疇,就不多說了。

文檔:

addslashes() Versus mysql_real_escape_string()
SQL Injection with MySQL
Advanced SQL Injection with MySQL
MySQL注入中導出字段內容的研究——通過注入導出WebShell

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved