sql注入主要是指通過在get、post請求參數中構造sql語句,以修改程序運行時所執行的sql語句,從而實現獲取、修改信息甚至是刪除數據的目的,sql被注入的原因主要是代碼編寫的有問題(有漏洞),只要平時注意在編寫與sql相關的代碼時養成良好的習慣,對可能被注入的sql語句加以防范,那么在大部分情況下是可以防范sql注入的。下面看下哪些不好的編碼習慣容易引起select語句被注入,並分析下防范措施。
注意:這里沒有完整的php代碼,可以大致假設一個場景:用戶可以通過類似下面的url地址http://localhost/user.php?username=yang或http://localhost/user.php?uid=yang,通過get方法來請求數據庫中的信息,數據庫中有user、article表。
1,sql語句中的替換變量不加引號
看下這條語句 $sql = "select uid, username from user where uid = $uid ";
替換變量不加引號,如果用戶輸入這樣的$uid:$uid = '1 and 1=2 union select * from article where aid = 1';
那么可以構造出這樣的sql
select uid, username from user where uid = 1 and 1=2 union select * from article where aid = 1
可以看到結合union,就可以對其他表中的數據進行查詢。
所以,sql語句中的變量應該要加上引號 $sql = "select uid, username from user where uid = '$uid'";
這樣即便被sql注入,被構造的sql語句也只會變成這樣:
select uid, username from user where uid = '1 and 1=2 union select * from article where aid = 1';
這樣構造出的uid就只能是sql語句中查詢參數的值,也就起不到注入作用了。
2,未對用戶的輸入進行過濾和轉義
(1)過濾,對數據進行過濾,將其轉換為自己需要的格式,或者判斷數據格式是否合法。判斷數據格式是否合法這個要按照自己定義的規則來進行,比如email地址格式、用戶名長度和組合、密碼長度和組合等,這里先不討論數據格式合法性的問題。下面先簡單看下格式轉換問題:
對於按id查找的sql,因為id一般為整數,所以可以先將用戶輸入的數據類型轉換為int,這樣即使用戶嘗試構造$uid為:
$uid = (int)'1 and 1=2 union select * from article where aid = 1' ,
它也會被轉換為數字,這在一定程度上能夠避免被注入。
(2)對於按如username字符串類型查找的sql,面臨的主要注入風險是通過在參數中加上單引號、sql注釋符、sql語句結束符等符號來構造sql,所以只要注意將這些字符進行轉義即可,也就是對用戶輸入的數據進行轉義,這里涉及到兩個函數:addslashes()和 addcslashes()。addslashes()可以對單引號'、雙引號"、反斜線\和NUL(NULL字符)進行轉義。addcslashes()可以自定義需要轉義的字符,下面來看下利用addcslashes()對用戶的輸入進行轉義。
比如下面這條sql語句:
$sql = "select uid, username from user where username = '{$username}' ";
在不進行轉義的時候,用戶可以構造$username如下: yang';SHOW TABLES-- inject
最后構造出如下的sql:
select uid, username from user where username = 'yang';SHOW TABLES-- inject';
現在我們用addcslashes()函數對$username進行轉義,
$username = isset($_GET['username']) ? addcslashes($_GET['username'], "'\"%_\\;-") : '';
注意上面的語句會對下面的字符進行轉義 ,可以根據實際需要轉義相應的字符。
' 單引號 " 雙引號 % 百分號 _ 下划線 \ 反斜線 ; 分號 - 小破折號
這時如果用戶構造的 yang';SHOW TABLES-- inject 就會變成這個樣子: yang\'\;SHOW TABLES\-\- inject ,構造的sql會變成這樣:
select uid, username from user where username = 'yang\'\;SHOW TABLES\-\- inject';
可以說是慘不忍睹了,sql注入也就失效了。
3,小結
上面只是簡單的分析了容易被sql注入的兩個不好的編程習慣和相應的防范,其實sql注入的方式、方法還有很多,所謂魔高一尺、道高一丈,需要學習的地方還有很多。
參考: