php資料庫安全——SQL注入及預防措施

來源:互聯網
上載者:User
很多 web 開發人員沒有注意到 SQL 查詢是可以被篡改的,因而把 SQL 查詢當作可信任的命令。殊不知道,SQL 查詢可以繞開存取控制,從而繞過身分識別驗證和許可權檢查。更有甚者,有可能通過 SQL 查詢去運行主機作業系統級的命令。

直接 SQL 命令注入就是攻擊者常用的一種建立或修改已有 SQL 陳述式的技術,從而達到取得隱藏資料,或覆蓋關鍵的值,甚至執行資料庫主機作業系統命令的目的。這是通過應用程式取得使用者輸入並與靜態參數組合成 SQL 查詢來實現的。下面將會給出一些真實的例子。

由於在缺乏對輸入的資料進行驗證,並且使用了超級使用者或其它有權建立新使用者的資料庫帳號來串連,攻擊者可以在資料庫中建立一個超級使用者。

Example #1 一段實現資料分頁顯示的代碼……也可以被用作建立一個超級使用者(PostgreSQL系統)。

<?php    $offset = $argv[0]; // 注意,沒有輸入驗證!    $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";    $result = pg_query($conn, $query);?>

一般的使用者會點擊 $offset 已被斌值的“上一頁”、“下一頁”的連結。原本代碼只會認為 $offset 是一個數值。然而,如果有人嘗試把以下語句先經過 urlencode() 處理,然後加入URL中的話:

0;insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)    select 'crack', usesysid, 't','t','crack'    from pg_shadow where usename='postgres';--

那麼他就可以建立一個超級使用者了。注意那個 0; 只不過是為了提供一個正確的位移量以便補充完整原來的查詢,使它不要出錯而已。

Note:

-- 是 SQL 的注釋標記,一般可以使用來它告訴 SQL 解譯器忽略後面的語句。

對顯示搜尋結果的頁面下手是一個能得到密碼的可行辦法。攻擊者所要做的只不過是找出哪些提交上去的變數是用於 SQL 陳述式並且處理不當的。而這類的變數通常都被用於SELECT 查詢中的條件陳述式,如 WHERE, ORDER BY, LIMIT 和 OFFSET。如果資料庫支援 UNION 構造的話,攻擊者還可能會把一個完整的 SQL 查詢附加到原來的語句上以便從任意資料表中得到密碼。因此,對密碼欄位加密是很重要的。

Example #2 顯示文章……以及一些密碼(任何資料庫系統)

<?php    $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 子句下手,這樣他們就可以更改資料表中的一些資料。這種情況下必須要知道資料庫的結構才能修改查詢成功進行。可以通過表單上的變數名對欄位進行猜測,或者進行暴力破解。對於存放使用者名稱和密碼的欄位,命名的方法並不多。

Example #3 從重設密碼……到獲得更多許可權(任何資料庫系統)

<?php    $query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";?>

但是惡意的使用者會把 ' or uid like'%admin%'; -- 作為變數的值提交給 $uid 來改變 admin 的密碼,或者把 $pwd 的值提交為 "hehehe', admin='yes', trusted=100 "(後面有個空格)去獲得更多的許可權。這樣做的話,查詢語句實際上就變成了:

<?php    // $uid == ' or uid like'%admin%'; --    $query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";    // $pwd == "hehehe', admin='yes', trusted=100 "    $query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE        ...;";?>

下面這個可怕的例子將會示範如何在某些資料庫上執行系統命令。

Example #4 攻擊資料庫所在主機的作業系統(MSSQL Server)

<?php    $query  = "SELECT * FROM products WHERE id LIKE '%$prod%'";    $result = mssql_query($query);?>

如果攻擊提交 a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- 作為變數 $prod的值,那麼 $query 將會變成

<?php    $query = "SELECT * FROM products WHERE id LIKE '%a%'        exec master..xp_cmdshell 'net user test testpass /ADD'--";    $result = mssql_query($query);?>

MSSQL 伺服器會執行這條 SQL 陳述式,包括它後面那個用於向系統添加使用者的命令。如果這個程式是以 sa 運行而 MSSQLSERVER 服務又有足夠的許可權的話,攻擊者就可以獲得一個系統帳號來訪問主機了。

Note:

雖然以上的例子是針對某一特定的資料庫系統的,但是這並不代表不能對其它資料庫系統實施類似的攻擊。使用不同的方法,各種資料庫都有可能遭殃。

預防措施

也許有人會自我安慰,說攻擊者要知道資料庫結構的資訊才能實施上面的攻擊。沒錯,確實如此。但沒人能保證攻擊者一定得不到這些資訊,一但他們得到了,資料庫有泄露的危險。如果你在用開放原始碼的軟體包來訪問資料庫,比如論壇程式,攻擊者就很容得到到相關的代碼。如果這些代碼設計不良的話,風險就更大了。

這些攻擊總是建立在發掘安全意識不強的代碼上的。所以,永遠不要信任外界輸入的資料,特別是來自於用戶端的,包括選擇框、表單隱藏欄位和 cookie。就如上面的第一個例子那樣,就算是正常的查詢也有可能造成災難。

永遠不要使用超級使用者或所有者帳號去串連資料庫。要用許可權被嚴格限制的帳號。

檢查輸入的資料是否具有所期望的資料格式。PHP 有很多可以用於檢查輸入的函數,從簡單的變數函數和字元類型函數(比如 is_numeric(), ctype_digit())到複雜的Perl 相容Regex函數都可以完成這個工作。

如果程式等待輸入一個數字,可以考慮使用 is_numeric() 來檢查,或者直接使用 settype() 來轉換它的類型,也可以用 sprintf() 把它格式化為數字。

Example #5 一個實現分頁更安全的方法

<?php    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);?>

使用資料庫特定的敏感字元轉義函數(比如 mysql_escape_string() 和 sql_escape_string())把使用者提交上來的非數字資料進行轉義。如果資料庫沒有專門的敏感字元轉義功能的話 addslashes() 和 str_replace() 可以代替完成這個工作。看看第一個例子,此例顯示僅在查詢的靜態部分加上引號是不夠的,查詢很容易被攻破。

要不擇手段避免顯示出任何有關資料庫的信心,尤其是資料庫結構。

也可以選擇使用資料庫的預存程序和預定義指標等特性來抽象數庫訪問,使使用者不能直接存取資料表和視圖。但這個辦法又有別的影響。

除此之外,在允許的情況下,使用代碼或資料庫系統儲存查詢日誌也是一個好辦法。顯然,日誌並不能防止任何攻擊,但利用它可以跟蹤到哪個程式曾經被嘗試攻擊過。日誌本身沒用,要查閱其中包含的資訊才行。畢竟,更多的資訊總比沒有要好。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.