PHP數(shù)據(jù)庫安全之SQL注入
發(fā)布日期:2021-12-28 14:55 | 文章來源:站長之家
$offset = $argv[0]; // 注意,沒有輸入驗證!
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
$result = pg_query($conn, $query);
?>
一般的用戶會點擊 $offset 已被斌值的“上一頁”、“下一頁”的鏈接。原本代碼只會認為 $offset 是一個數(shù)值。然而,如果有人嘗試把以下語句先經(jīng)過 urlencode() 處理,然后加入URL中的話:
0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
select 'crack', usesysid, 't','t','crack'
from pg_shadow where usename='postgres';
--
那么他就可以創(chuàng)建一個超級用戶了。注意那個 0; 只不過是為了提供一個正確的偏移量以便補充完整原來的查詢,使它不要出錯而已。
注: -- 是 SQL 的注釋標記,一般可以使用來它告訴 SQL 解釋器忽略后面的語句。
對顯示搜索結果的頁面下手是一個能得到密碼的可行辦法。攻擊者所要做的只不過是找出哪些提交上去的變量是用于 SQL 語句并且處理不當?shù)?。而這類的變量通常都被用于 SELECT 查詢中的條件語句,如 WHERE, ORDER BY, LIMIT 和 OFFSET。如果數(shù)據(jù)庫支持 UNION 構造的話,攻擊者還可能會把一個完整的 SQL 查詢附加到原來的語句上以便從任意數(shù)據(jù)表中得到密碼。因此,對密碼字段加密是很重要的。 例子 27-3. 顯示文章……以及一些密碼(任何數(shù)據(jù)庫系統(tǒng))
$query = "SELECT id, name, inserted, size FROM products WHERE size = '$size' ORDER BY $order LIMIT $limit, $offset;"; $result = odbc_exec($conn, $query); ?> 可以在原來的查詢的基礎上添加另一個 SELECT 查詢來獲得密碼: 'union select '1', concat(uname '-' passwd) as name, '1971-01-01', '0' from usertable; -- 假如上述語句(使用 ' 和 --)被加入到 $query 中的任意一個變量的話,那么就麻煩了。 SQL 中的 UPDATE 也會受到攻擊。這種查詢也可能像上面的例子那樣被插入或附加上另一個完整的請求。但是攻擊者更愿意對 SET 子句下手,這樣他們就可以更改數(shù)據(jù)表中的一些數(shù)據(jù)。這種情況下必須要知道數(shù)據(jù)庫的結構才能修改查詢成功進行??梢酝ㄟ^表單上的變量名對字段進行猜測,或者進行暴力破解。對于存放用戶名和密碼的字段,命名的方法并不多。 例子 27-4. 從重設密碼……到獲得更多權限(任何數(shù)據(jù)庫系統(tǒng))
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';"; ?> 但是惡意的用戶會把 ' or uid like'璵in%'; -- 作為變量的值提交給 $uid 來改變 admin 的密碼,或者把 $pwd 的值提交為 "hehehe', admin='yes', trusted=100 "(后面有個空格)去獲得更多的權限。這樣做的話,查詢語句實際上就變成了:
// $uid == ' or uid like'璵in%'; -- $query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '璵in%'; --"; // $pwd == "hehehe', admin='yes', trusted=100 " $query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE ...;"; ?> 下面這個可怕的例子將會演示如何在某些數(shù)據(jù)庫上執(zhí)行系統(tǒng)命令。 例子 27-5. 攻擊數(shù)據(jù)庫所在主機的操作系統(tǒng)(MSSQL Server)
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'"; $result = mssql_query($query); ?> 如果攻擊提交 a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- 作為變量 $prod的值,那么 $query 將會變成
$query = "SELECT * FROM products WHERE id LIKE '%a%' exec master..xp_cmdshell 'net user test testpass /ADD'--"; $result = mssql_query($query); ?> MSSQL 服務器會執(zhí)行這條 SQL 語句,包括它后面那個用于向系統(tǒng)添加用戶的命令。如果這個程序是以 sa 運行而 MSSQLSERVER 服務又有足夠的權限的話,攻擊者就可以獲得一個系統(tǒng)帳號來訪問主機了。 注: 雖然以上的例子是針對某一特定的數(shù)據(jù)庫系統(tǒng)的,但是這并不代表不能對其它數(shù)據(jù)庫系統(tǒng)實施類似的攻擊。使用不同的方法,各種數(shù)據(jù)庫都有可能遭殃。 預防措施 也許有人會自我安慰,說攻擊者要知道數(shù)據(jù)庫結構的信息才能實施上面的攻擊。沒錯,確實如此。但沒人能保證攻擊者一定得不到這些信息,一但他們得到了,數(shù)據(jù)庫有泄露的危險。如果你在用開放源代碼的軟件包來訪問數(shù)據(jù)庫,比如論壇程序,攻擊者就很容得到到相關的代碼。如果這些代碼設計不良的話,風險就更大了。 這些攻擊總是建立在發(fā)掘安全意識不強的代碼上的。所以,永遠不要信任外界輸入的數(shù)據(jù),特別是來自于客戶端的,包括選擇框、表單隱藏域和cookie。就如上面的第一個例子那樣,就算是正常的查詢也有可能造成災難。 永遠不要使用超級用戶或所有者帳號去連接數(shù)據(jù)庫。要用權限被嚴格限制的帳號。 檢查輸入的數(shù)據(jù)是否具有所期望的數(shù)據(jù)格式。PHP 有很多可以用于檢查輸入的函數(shù),從簡單的變量函數(shù)和字符類型函數(shù)(比如 is_numeric(),ctype_digit())到復雜的 Perl 兼容正則表達式函數(shù)都可以完成這個工作。 如果程序等待輸入一個數(shù)字,可以考慮使用 is_numeric() 來檢查,或者直接使用 settype() 來轉換它的類型,也可以用 sprintf() 把它格式化為數(shù)字。 例子 27-6. 一個實現(xiàn)分頁更安全的方法
settype($offset, 'integer'); $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;"; // 請注意格式字符串中的 %d,如果用 %s 就毫無意義了 $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;", $offset); ?> 使用數(shù)據(jù)庫特定的敏感字符轉義函數(shù)(比如 mysql_escape_string() 和 sql_escape_string())把用戶提交上來的非數(shù)字數(shù)據(jù)進行轉義。如果數(shù)據(jù)庫沒有專門的敏感字符轉義功能的話 addslashes() 和 str_replace() 可以代替完成這個工作。看看第一個例子,此例顯示僅在查詢的靜態(tài)部分加上引號是不夠的,查詢很容易被攻破。 要不擇手段避免顯示出任何有關數(shù)據(jù)庫的信心,尤其是數(shù)據(jù)庫結構。參見錯誤報告和錯誤處理函數(shù)。 也可以選擇使用數(shù)據(jù)庫的存儲過程和預定義指針等特性來抽象數(shù)庫訪問,使用戶不能直接訪問數(shù)據(jù)表和視圖。但這個辦法又有別的影響。 除此之外,在允許的情況下,使用代碼或數(shù)據(jù)庫系統(tǒng)保存查詢?nèi)罩疽彩且粋€好辦法。顯然,日志并不能防止任何攻擊,但利用它可以跟蹤到哪個程序曾經(jīng)被嘗試攻擊過。日志本身沒用,要查閱其中包含的信息才行。畢竟,更多的信息總比沒有要好。 add a note User Contributed Notes SQL 注入 17-Mar-2006 01:48 If you use the PEAR package and prepare() / execute() your queries, you will hardly have to worry about any of this. Of course, it's still a good idea to make sure you're putting valid data in your database... bee at askbee dot net 17-Nov-2005 06:52 A great article of how to avoid sql injection http://www.askbee.net/articles/php/SQL_Injection/sql_injection.html anonymous 26-Jan-2005 04:42 Here is a useful class that deals with SQL injection: http://www.phpinsider.com/php/code/SafeSQL/
$query = "SELECT id, name, inserted, size FROM products WHERE size = '$size' ORDER BY $order LIMIT $limit, $offset;"; $result = odbc_exec($conn, $query); ?> 可以在原來的查詢的基礎上添加另一個 SELECT 查詢來獲得密碼: 'union select '1', concat(uname '-' passwd) as name, '1971-01-01', '0' from usertable; -- 假如上述語句(使用 ' 和 --)被加入到 $query 中的任意一個變量的話,那么就麻煩了。 SQL 中的 UPDATE 也會受到攻擊。這種查詢也可能像上面的例子那樣被插入或附加上另一個完整的請求。但是攻擊者更愿意對 SET 子句下手,這樣他們就可以更改數(shù)據(jù)表中的一些數(shù)據(jù)。這種情況下必須要知道數(shù)據(jù)庫的結構才能修改查詢成功進行??梢酝ㄟ^表單上的變量名對字段進行猜測,或者進行暴力破解。對于存放用戶名和密碼的字段,命名的方法并不多。 例子 27-4. 從重設密碼……到獲得更多權限(任何數(shù)據(jù)庫系統(tǒng))
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';"; ?> 但是惡意的用戶會把 ' or uid like'璵in%'; -- 作為變量的值提交給 $uid 來改變 admin 的密碼,或者把 $pwd 的值提交為 "hehehe', admin='yes', trusted=100 "(后面有個空格)去獲得更多的權限。這樣做的話,查詢語句實際上就變成了:
// $uid == ' or uid like'璵in%'; -- $query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '璵in%'; --"; // $pwd == "hehehe', admin='yes', trusted=100 " $query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE ...;"; ?> 下面這個可怕的例子將會演示如何在某些數(shù)據(jù)庫上執(zhí)行系統(tǒng)命令。 例子 27-5. 攻擊數(shù)據(jù)庫所在主機的操作系統(tǒng)(MSSQL Server)
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'"; $result = mssql_query($query); ?> 如果攻擊提交 a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- 作為變量 $prod的值,那么 $query 將會變成
$query = "SELECT * FROM products WHERE id LIKE '%a%' exec master..xp_cmdshell 'net user test testpass /ADD'--"; $result = mssql_query($query); ?> MSSQL 服務器會執(zhí)行這條 SQL 語句,包括它后面那個用于向系統(tǒng)添加用戶的命令。如果這個程序是以 sa 運行而 MSSQLSERVER 服務又有足夠的權限的話,攻擊者就可以獲得一個系統(tǒng)帳號來訪問主機了。 注: 雖然以上的例子是針對某一特定的數(shù)據(jù)庫系統(tǒng)的,但是這并不代表不能對其它數(shù)據(jù)庫系統(tǒng)實施類似的攻擊。使用不同的方法,各種數(shù)據(jù)庫都有可能遭殃。 預防措施 也許有人會自我安慰,說攻擊者要知道數(shù)據(jù)庫結構的信息才能實施上面的攻擊。沒錯,確實如此。但沒人能保證攻擊者一定得不到這些信息,一但他們得到了,數(shù)據(jù)庫有泄露的危險。如果你在用開放源代碼的軟件包來訪問數(shù)據(jù)庫,比如論壇程序,攻擊者就很容得到到相關的代碼。如果這些代碼設計不良的話,風險就更大了。 這些攻擊總是建立在發(fā)掘安全意識不強的代碼上的。所以,永遠不要信任外界輸入的數(shù)據(jù),特別是來自于客戶端的,包括選擇框、表單隱藏域和cookie。就如上面的第一個例子那樣,就算是正常的查詢也有可能造成災難。 永遠不要使用超級用戶或所有者帳號去連接數(shù)據(jù)庫。要用權限被嚴格限制的帳號。 檢查輸入的數(shù)據(jù)是否具有所期望的數(shù)據(jù)格式。PHP 有很多可以用于檢查輸入的函數(shù),從簡單的變量函數(shù)和字符類型函數(shù)(比如 is_numeric(),ctype_digit())到復雜的 Perl 兼容正則表達式函數(shù)都可以完成這個工作。 如果程序等待輸入一個數(shù)字,可以考慮使用 is_numeric() 來檢查,或者直接使用 settype() 來轉換它的類型,也可以用 sprintf() 把它格式化為數(shù)字。 例子 27-6. 一個實現(xiàn)分頁更安全的方法
settype($offset, 'integer'); $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;"; // 請注意格式字符串中的 %d,如果用 %s 就毫無意義了 $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;", $offset); ?> 使用數(shù)據(jù)庫特定的敏感字符轉義函數(shù)(比如 mysql_escape_string() 和 sql_escape_string())把用戶提交上來的非數(shù)字數(shù)據(jù)進行轉義。如果數(shù)據(jù)庫沒有專門的敏感字符轉義功能的話 addslashes() 和 str_replace() 可以代替完成這個工作。看看第一個例子,此例顯示僅在查詢的靜態(tài)部分加上引號是不夠的,查詢很容易被攻破。 要不擇手段避免顯示出任何有關數(shù)據(jù)庫的信心,尤其是數(shù)據(jù)庫結構。參見錯誤報告和錯誤處理函數(shù)。 也可以選擇使用數(shù)據(jù)庫的存儲過程和預定義指針等特性來抽象數(shù)庫訪問,使用戶不能直接訪問數(shù)據(jù)表和視圖。但這個辦法又有別的影響。 除此之外,在允許的情況下,使用代碼或數(shù)據(jù)庫系統(tǒng)保存查詢?nèi)罩疽彩且粋€好辦法。顯然,日志并不能防止任何攻擊,但利用它可以跟蹤到哪個程序曾經(jīng)被嘗試攻擊過。日志本身沒用,要查閱其中包含的信息才行。畢竟,更多的信息總比沒有要好。 add a note User Contributed Notes SQL 注入 17-Mar-2006 01:48 If you use the PEAR package and prepare() / execute() your queries, you will hardly have to worry about any of this. Of course, it's still a good idea to make sure you're putting valid data in your database... bee at askbee dot net 17-Nov-2005 06:52 A great article of how to avoid sql injection http://www.askbee.net/articles/php/SQL_Injection/sql_injection.html anonymous 26-Jan-2005 04:42 Here is a useful class that deals with SQL injection: http://www.phpinsider.com/php/code/SafeSQL/
版權聲明:本站文章來源標注為YINGSOO的內(nèi)容版權均為本站所有,歡迎引用、轉載,請保持原文完整并注明來源及原文鏈接。禁止復制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務器上建立鏡像,否則將依法追究法律責任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學習參考,不代表本站立場,如有內(nèi)容涉嫌侵權,請聯(lián)系alex-e#qq.com處理。
相關文章