何為注入?
比如我們在查詢資料庫的時候,我們通過文章的id號來取出這篇文章的所有資訊。那麼SQL語句可以這樣寫:
代碼如下 |
複製代碼 |
select * from blog where id=5 |
id的值通過使用者的操作來傳遞,一般是GET方式,形如read.php?id=5。這樣看起來是沒有任何問題,但是如果我們稍微改下SQL語句:
代碼如下 |
複製代碼 |
select * from blog where id=5 or 1=1 |
1=1這個是恒等的,那麼這條語句就會取出所有的文章。要修改這個只需要改一下GET的傳值即可:read.php?id='5 or 1=1';注意這兩個單引號...所以最簡單的就是我們可以通過直接把參數改為單引號來查看這個連結是否存在注入。當然,非法使用者看到所有的文章並不要緊,但是如果這個表是儲存帳號和密碼的呢?
2.如何防範注入?
說到底,防範注入的根本就在於字元的過濾,因為非法使用者一般都是通過構造URL來傳值的,如果我們過濾了他傳進來的非法參數,這非法的SQL語句就不會執行,那麼我們也就防止網站被注入!
PHP內建的過濾字串還是相當不錯的,先看看具體代碼:
代碼如下 |
複製代碼 |
function safe($s) { if(!get_magic_quotes_gpc()) { if(is_array($s)) foreach($s as $key=>$value) $s[$key] = addslashes($value); else $s=addslashes($s); } return $s; } function html_safe($s) { return nl2br(htmlspecialchars(safe($s) )) ; } |
如果你不知道上面用到的幾個內建函數,也懶了去查手冊的話,那我就說下這幾個函數:
magic_quotes_gpc這個稱為魔術引號,如果這個功能開啟,那麼當向資料庫中插入資料時,魔術引號所做的就是自動對所有的 GET、POST、COOKIE 資料運用 addslashes() 函數。get_magic_quotes_gpc()就是用來擷取伺服器上這個功能是否開啟的:如果開啟了,那麼直接返回資料;如果沒開啟,那麼手動對參數進行addslashes()轉義。這樣就可以防止雙層轉義~
addslashes -- 使用反斜線引用字串。描述:string addslashes ( string str );返回字串,該字串為了資料庫查詢語句等的需要在某些字元前加上了反斜線。這些字元是單引號(')、雙引號(")、反斜線()與 NUL(NULL 字元)。 一個使用 addslashes() 的例子是當你要往資料庫中輸入資料時。例如,將名字 O'reilly 插入到資料庫中,這就需要對其進行轉義。大多資料庫使用 作為轉義符:O'reilly。這樣可以將資料放入資料庫中,而不會插入額外的 。當 PHP 指令 magic_quotes_sybase 被設定成 on 時,意味著插入 ' 時將使用 ' 進行轉義。
下面的那個htmlspecialchars就是對Html中的字元進行轉換,比如說將‘&’轉成‘&’,,將‘<’轉成‘<’。nl2br這個是將斷行符號換行轉換成<br/>,這個在使用者輸入評論之類的資訊時候用得比較多。
通過上面的幾個函數,我們已經可以過濾一些簡單的注入了。另外再說幾個小的方面:
對於最開始的那個例子,實際上改進的地方很多,比如寫成這樣看起來應該更規範一些:
代碼如下 |
複製代碼 |
SELECT * FROM `blog` WHERE `id`='$id' |
對於SQL的關鍵字我們用大寫來表示,對於資料庫中的表和欄位我們用小寫,另外在欄位名和表名上加上“·”這個符號(鍵盤上數字1左邊的那個鍵上),並且在進來的id上我們用單引號引起來。
對於這樣的傳進來參數是數字類型的,我們可以對$_GET到的值進行強制轉換。但我更習慣這樣:
代碼如下 |
複製代碼 |
$id = $_GET['id']*1; //擷取文章的id,用來顯示文章資訊 if($id == 0){ echo "ERROR..."; exit(); } |
如果一發現傳進來的不是數字,那麼很大可能性性是存在問題的參數,那麼我們直接給出錯誤提示然後退出就行,這樣再省得再去給非法使用者執行資料庫查詢操作了。
最後我們看一下JBlog中的一個處理注入的地方:
includecommon.php的38行
代碼如下 |
複製代碼 |
if ( !get_magic_quotes_gpc() ) { $_GET = add_slashes($_GET); $_POST = add_slashes($_POST); $_COOKIE = add_slashes($_COOKIE); } |
includefunc_global.php的194行
代碼如下 |
複製代碼 |
//addslashes function add_slashes($string) { if (!is_array($string)) return addslashes($string); foreach ($string as $key => $val) { $string[$key] = add_slashes($val); } return $string; }
|
當然,這應該只是一部分,其他的應該也大同小異。