0、導讀
在MySQL里,如何識別並且避免發生SQL注入風險
1、關於SQL注入
互聯網很危險,信息及數據安全很重要,SQL注入是最常見的入侵手段之一,其技術門檻低、成本低、收益大,頗受各層次的黑客們所青睞。
一般來說,SQL注入的手法是利用各種機會將惡意SQL代碼添加到程序參數中,並最終被服務器端執行,造成不良后果。
例如,我們訪問接口 http://imysql.com/user.php?userid=123 來根據userid獲取用戶信息,假設程序中是這么處理的:
$sql = “SELECT * FROM user WHERE userid = $_GET[userid] “;
上面這段代碼看起來既low有很xx對吧,尤其是在雙引號里面還可以直接引用數據類型變量,所以說php是世界上最好的語言一點不為過,哈哈(其實我早期也寫過幾年php的)。
這時候,如果我們傳遞進去的參數改成這樣:http://imysql.com/user.php?userid=123 or 1=1 ,這就會 導致SQL條件永遠成立 ,所有的數據都會被讀取出來。又或者可以傳遞這樣的參數:http://imysql.com/user.php?userid= 123 or if(now()=sysdate(),sleep(5),1) ,這時候不但所有的數據都會被讀取到,也會讓這個SQL執行完畢后再等待5秒才能返回,黑客可據此來判斷這個SQL注入探測是否成功。
在上面這個例子中,其實我們只需要對用戶輸入的參數進行簡單的類型判斷和控制,即可快速避免被注入的風險,例如改成下面這樣就可以了:
$userid = intval(strim($_GET[‘userid’]));
$sql = “SELECT * FROM user WHERE userid = “ . mysql_real_escape_string($userid);
可見,至少基礎的SQL注入並不難防范,只要在各個層面都做足工作就可以。而簡單的SQL盲注(就是亂拳打死老師傅的玩法)已經可以采用 sqlmap 之類的輔助工具來做了,完全不需要人工執行。
2、如何防范
上面提到過sqlmap,它既可以作為SQL盲注的工具,也可以在新項目上線前內部掃一次,提前發現潛在漏洞,及時修補,反過來為我們所用。其他可以檢測sql注入漏洞的知名掃描工具有: SQLIer、SQLID、SQL Power Injector、SQLNinja 。
我們也可以自己通過頻繁掃描當前執行的SQL列表,根據一些關鍵字來判斷是否發生了SQL注入或潛在風險,常見的關鍵字有:
-
SLEEP() — 一般的SQL盲注都會伴隨SLEEP()函數出現,而且一般至少SLEEP 5秒以上
-
MID()
-
CHAR()
-
ORD()
-
SYSDATE()
-
SUBSTRING()
-
DATABASES()
-
SCHEMA()
-
USER()
-
VERSION()
-
CURRENT_USER()
-
LOAD_FILE()
-
OUTFILE/DUMPFILE
-
INFORMATION_SCHEMA
-
TABLE_NAME
-
fwrite()/fopen()/file_get_contents() — 這幾個是PHP文件操作函數
我們可以以較高頻率檢查當前的活躍SQL命令,一旦發現上述關鍵字,可以立即記錄下來並觸發告警,通知管理員及時人工確認處理,甚至也可以先直接自動殺掉這些SQL查詢(可以用 pt-kill 工具來做到這點,也可以自行開發),以防萬一,少給黑客留機會。
還有,我們 建議把選項 safe-update/sql_safe_updates 設置為 1,防止沒有任何 WHERE 條件的誤操作更新,將全表數據都寫錯 。
3、其他建議
防范SQL注入只是數據安全保護工作很小的一部分,只要做好基本功就可以防住至少80%以上的SQL注入探測。
在app server層,以PHP開發語言為例,除了上面提到的規范用戶輸入類型外,還可以 改成用 sprintf() 函數來格式化構造 SQL 語句 ,也可以一定程度防范SQL注入。還可以 修改 php cgi 程序的運行屬主為普通用戶 ,最起碼不能使用 root 用戶,避免因為代碼層不嚴謹導致被黑客上傳可執行 php 程序代碼文件。還可以 把php中的遠程文件調用權限關閉,把選項 allow_url_fopen、allow_url_include 均設置為 off,並限定php可以打開的文件目錄 ,不允許跨區域訪問敏感文件。
除了在代碼層面做好數據類型判斷、用戶輸入判斷外,還可以在web server層加上過濾策略,比如在nginx上啟用WAF插件。或者,也可以購買IDC運營商、雲主機提供商提供的商業解決方案。對於重視數據安全的企業來說,花點錢保平安更為重要。
4、附錄
下面是一些常見SQL注入參考案例:
案例1:SELECT * FROM t WHERE a LIKE ‘%xxx%’ OR (IF(NOW=SYSDATE(), SLEEP(5), 1)) OR b LIKE ‘1=1 ‘;
案例2:SELECT * FROM t WHERE a > 0 AND b IN(497 AND (SELECT * FROM (SELECT(SLEEP(20)))a) );
案例3:SELECT * FROM t WHERE a=1 and b in (1234 ,(SELECT (CASE WHEN (5=5) THEN SLEEP(5) ELSE 5*(SELECT 5 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END)) );
上一頁