sql注入攻擊

轉載::

常見攻擊方式

一般說來,在Web安全領域,常見的攻擊方式大概有以下幾種:
1、SQL注入攻擊
2、跨站腳本攻擊 - XSS
3、跨站僞造請求攻擊 - CSRF
4、文件上傳漏洞攻擊

5、分佈式拒絕服務攻擊 - DDOS


SQL注入產生的原因,和棧溢出、XSS等很多其他的攻擊方法類似,就是未經檢查或者未經充分檢查用戶輸入數據意外變成了代碼被執行也就是,SQL注入是用戶輸入的數據,在拼接SQL語句的過程中,超越了數據本身,成爲了SQL語句查詢邏輯的一部分,然後這樣被拼接出來的SQL語句被數據庫執行,產生了開發者預期之外的動作。所以從根本上防止上述類型攻擊的手段,還是避免數據變成代碼被執行,時刻分清代碼和數據的界限。而具體到SQL注入來說,被執行的惡意代碼是通過數據庫的SQL解釋引擎編譯得到的,所以只要避免用戶輸入的數據被數據庫系統編譯就可以了。

現在的數據庫系統都提供SQL語句的預編譯(prepare)和查詢參數綁定功能,在SQL語句中放置佔位符'?',然後將帶有佔位符的SQL語句傳給數據庫編譯,執行的時候纔將用戶輸入的數據作爲執行的參數傳給用戶。這樣的操作不僅使得SQL語句在書寫的時候不再需要拼接,看起來也更直接,而且用戶輸入的數據也沒有機會被送到數據庫的SQL解釋器被編譯執行,也不會越權變成代碼。

假設我們可以通過 http://localhost/test/userinfo.php?username=plhwin 這個URL來訪問到具體某個會員的詳情,正常情況下,如果瀏覽器裏傳入的username是合法的,那麼SQL語句會執行:

SELECT uid,username FROM user WHERE username='plhwin'

但是,如果用戶在瀏覽器裏把傳入的username參數變爲 plhwin';SHOW TABLES-- hack,也就是當URL變爲 http://localhost/test/userinfo.php?username=plhwin';SHOW TABLES-- hack 的時候,此時我們程序實際執行的SQL語句變成了:

SELECT uid,username FROM user WHERE username='plhwin';SHOW TABLES-- hack'

注意:在MySQL中,最後連續的兩個減號表示忽略此SQL減號後面的語句(然後後面加兩個-,這意味着註釋,它將後面的語句註釋,讓他們不起作用,這樣語句永遠都能正確執行,用戶輕易騙過系統,獲取合法身份。),我本機的MySQL版本號爲5.6.12,目前幾乎所有SQL注入實例都是直接採用兩個減號結尾,但是實際測試,這個版本號的MySQL要求兩個減號後面必須要有空格才能正常注入,而瀏覽器是會自動刪除掉URL尾部空格的,所以我們的注入會在兩個減號後面統一添加任意一個字符或單詞,本篇文章的SQL注入實例統一以 -- hack 結尾。

經過上面的SQL注入後,原本想要執行查詢會員詳情的SQL語句,此時還額外執行了 SHOW TABLES; 語句,這顯然不是開發者的本意,此時可以在瀏覽器裏看到頁面的輸出:

Array
(
    [0] => Array
        (
            [uid] => 1
            [username] => plhwin
        )
    [1] => Array
        (
            [Tables_in_demo] => user
        )
)

你能清晰的看到,除了會員的信息,數據庫表的名字user也被打印在了頁面上,如果作惡的黑客此時將參數換成 plhwin';DROP TABLE user-- hack,那將產生災難性的嚴重結果,當你在瀏覽器中執行 http://localhost/test/userinfo.php?username=plhwin';DROP TABLE user-- hack 這個URL後,你會發現整個 user 數據表都消失不見了。

此時如果輸入正確的用戶名 plhwin 和密碼 123456,執行的SQL語句爲:

SELECT uid,username FROM user WHERE username='plhwin' AND password='e10adc3949ba59abbe56e057f20f883e'

上面語句沒有任何問題,可以看到頁面打印出了登錄成功後的會員信息,但如果有搗蛋鬼輸入的用戶名爲 plhwin' AND 1=1-- hack,密碼隨意輸入,比如 aaaaaa,那麼拼接之後的SQL查詢語句就變成了如下內容:

SELECT uid,username FROM user WHERE username='plhwin' AND 1=1-- hack' AND password='0b4e7a0e5fe84ad35fb5f95b9ceeac79'

執行上面的SQL語句,因爲 1=1 是永遠成立的條件,這意味着黑客只需要知道別人的會員名,無需知道密碼就能順利登錄到系統。

如何確定SQL注入漏洞

通過以上的實例,我們仍然還會有疑問:黑客並不知道我們程序代碼的邏輯和SQL語句的寫法,他是如何確定一個網站是否存在SQL注入漏洞呢?一般說來有以下2種途徑:

1、錯誤提示

如果目標Web網站開啓了錯誤顯示,攻擊者就可以通過反覆調整發送的參數、查看頁面打印的錯誤信息,推測出Web網站使用的數據庫和開發語言等重要信息。

2、盲注

除非運維人員疏忽,否則大部分的Web運營網站應該都關閉了錯誤提示信息,此時攻擊者一般會採用盲注的技巧來進行反覆的嘗試判斷。 仍然以上面的數據表user爲例,我們之前的查看會員詳情頁面的url地址爲 userinfo.php?username=plhwin,此時黑客分別訪問 userinfo.php?username=plhwin' AND 1=1-- hack userinfo.php?username=plhwin' AND 1=2-- hack,如果前者訪問能返回正常的信息而後者不能,就基本可以判斷此網站存在SQL注入漏洞,因爲後者的 1=2 這個表達式永遠不成立,所以即使username傳入了正確的參數也無法通過,由此可以推斷這個頁面存在SQL注入漏洞,並且可以通過username參數進行注入。

如何防禦SQL注入

1、對於服務器配置層面的防範,應該保證生產環境的Webserver是關閉錯誤信息的,比如PHP在生產環境的配置文件php.ini中的display_errors應該設置爲Off,這樣就關閉了錯誤提示,下面我們更多的從編碼的角度來看看如何防範SQL注入。

但凡有SQL注入漏洞的程序,都是因爲程序要接受來自客戶端用戶輸入的變量或URL傳遞的參數,並且這個變量或參數是組成SQL語句的一部分,對於用戶輸入的內容或傳遞的參數,我們應該要時刻保持警惕,這是安全領域裏的「外部數據不可信任」的原則,縱觀Web安全領域的各種攻擊方式,大多數都是因爲開發者違反了這個原則而導致的,所以自然能想到的,就是從變量的檢測、過濾、驗證下手,確保變量是開發者所預想的。
1、檢查變量數據類型和格式

如果你的SQL語句是類似where id={$id}這種形式,數據庫裏所有的id都是數字,那麼就應該在SQL被執行前,檢查確保變量id是int類型;如果是接受郵箱,那就應該檢查並嚴格確保變量一定是郵箱的格式,其他的類型比如日期、時間等也是一個道理。總結起來:只要是有固定格式的變量,在SQL語句執行前,應該嚴格按照固定格式去檢查,確保變量是我們預想的格式,這樣很大程度上可以避免SQL注入攻擊。

2、過濾特殊符號

對於無法確定固定格式的變量,一定要進行特殊符號過濾或轉義處理。以PHP爲例,通常是採用addslashes函數,它會在指定的預定義字符前添加反斜槓轉義,這些預定義的字符是:單引號 (') 雙引號 (") 反斜槓 (\) NULL。

來看2條SQL語句:

$uid = isset($_GET['uid']) ? $_GET['uid'] : 0;
$uid = addslashes(uid);
$sql = "SELECT uid,username FROM user WHERE uid='{$uid}'";//此處多增加引號

以及

$uid = isset($_GET['uid']) ? $_GET['uid'] : 0;
$uid = addslashes(uid);
$sql = "SELECT uid,username FROM user WHERE uid={$uid}";
上面兩個查詢語句都經過了php的addslashes函數過濾轉義,但在安全性上卻大不相同,在MySQL中,對於int類型字段的條件查詢,上面個語句的查詢效果完全一樣,由於第一句SQL的變量被單引號包含起來,SQL注入的時候,黑客面臨的首要問題是必須要先閉合前面的單引號,這樣才能使後面的語句作爲SQL執行,並且還要註釋掉原SQL語句中的後面的單引號,這樣纔可以成功注入,由於代碼裏使用了addslashes函數,黑客的攻擊會無從下手,但第二句沒有用引號包含變量,那黑客也不用考慮去閉合、註釋,所以即便同樣採用addslashes轉義,也還是存在SQL攻擊漏洞。
默認情況下,PHP 指令 magic_quotes_gpc 爲 on,系統會對所有的 GET、POST 和 COOKIE 數據自動運行 addslashes() 。不要對已經被 magic_quotes_gpc 轉義過的字符串使用 addslashes() ,因爲這樣會導致雙層轉義。

對於PHP程序+MySQL構架的程序,在動態的SQL語句中,使用單引號把變量包含起來配合addslashes函數是應對SQL注入攻擊的有效手段,但這做的還不夠,像上面的2條SQL語句,根據「檢查數據類型」的原則,uid都應該經過intval函數格式爲int型,這樣不僅能有效避免第二條語句的SQL注入漏洞,還能使得程序看起來更自然,尤其是在NoSQL(如MongoDB)中,變量類型一定要與字段類型相匹配纔可以。

從上面可以看出,第二個SQL語句是有漏洞的,不過由於使用了addslashes函數,你會發現黑客的攻擊語句也存在不能使用特殊符號的條件限制,類似where username='plhwin'這樣的攻擊語句是沒法執行的,但是黑客可以將字符串轉爲16進制編碼數據或使用char函數進行轉化,同樣能達到相同的目的,如果對這部分內容感興趣,可以(http://cbb.sjtu.edu.cn/course/database/lab8.htm)這裏查看。而且由於SQL保留關鍵字,如「HAVING」、「ORDER BY」的存在,即使是基於黑白名單的過濾方法仍然會有或多或少問題,那麼是否還有其他方法來防禦SQL注入呢?

3、綁定變量,使用預編譯語句

實際上,綁定變量使用預編譯語句是預防SQL注入的最佳方式,使用預編譯的SQL語句語義不會發生改變,在SQL語句中,變量用問號?表示,黑客即使本事再大,也無法改變SQL語句的結構,像上面例子中,username變量傳遞的 plhwin' AND 1=1-- hack 參數,也只會當作username字符串來解釋查詢,從根本上杜絕了SQL注入攻擊的發生。

數據庫信息加密安全

在Web開發中,傳統的加解密大致可以分爲三種:

1、對稱加密:

即加密方和解密方都使用相同的加密算法和密鑰,這種方案的密鑰的保存非常關鍵,因爲算法是公開的,而密鑰是保密的,一旦密匙泄露,黑客仍然可以輕易解密。常見的對稱加密算法有:AES、DES等。

2、非對稱加密:

即使用不同的密鑰來進行加解密,密鑰被分爲公鑰和私鑰,用私鑰加密的數據必須使用公鑰來解密,同樣用公鑰加密的數據必須用對應的私鑰來解密,常見的非對稱加密算法有:RSA等。

3、不可逆加密:

利用哈希算法使數據加密之後無法解密回原數據,這樣的哈希算法常用的有:md5、SHA-1等。

在我們上面登錄系統的示例代碼中,$md5password = md5($password); 從這句代碼可以看到採用了md5的不可逆加密算法來存儲密碼,這也是多年來業界常用的密碼加密算法,但是這仍然不安全。爲什麼呢?

這是因爲md5加密有一個特點:同樣的字符串經過md5哈希計算之後生成的加密字符串也是相同的,由於業界採用這種加密的方式由來已久,黑客們也準備了自己強大的md5彩虹表來逆向匹配加密前的字符串,這種用於逆向反推MD5加密的彩虹表在互聯網上隨處可見,在Google裏使用md5 解密作爲關鍵詞搜索,一下就能找到md5在線破解網站,把我們插入用戶數據時候的MD5加密字符串e10adc3949ba59abbe56e057f20f883e填入進去,瞬間就能得到加密前的密碼:123456。當然也並不是每一個都能成功,但可以肯定的是,這個彩虹表會越來越完善。

所以,我們有迫切的需求採用更好的方法對密碼數據進行不可逆加密,通常的做法是爲每個用戶確定不同的密碼加鹽(salt)後,再混合用戶的真實密碼進行md5加密,如以下代碼:

小結

1、不要隨意開啓生產環境中Webserver的錯誤顯示。
2、
永遠不要信任來自用戶端的變量輸入,有固定格式的變量一定要嚴格檢查對應的格式,沒有固定格式的變量需要對引號等特殊字符進行必要的過濾轉義
3、
使用預編譯綁定變量的SQL語句
4、做好數據庫帳號權限管理。
5、嚴格加密處理用戶的機密信息。

根治方法:

1、儘量不要在應用層拼接SQL字符串

2、必須拼接字符串的時候對參數做好過濾

3、認真檢查是否存在例外

對於MySQL等開源數據庫,不允許不帶where條件(或者where條件恆爲true)的delete和update,即safe update模式,通過定製patch的方式限制用戶修改的數據行數,在sql中增加hint傳遞期望修改數據的數目,如果真實更新數據與目標不符,回滾操作

備份很重要,即使發生這類悲劇,通過上一次備份重建數據庫和重放最近更新來挽救

時隔很久看自己發的都感覺搞笑,目前我是這樣做的:

把每一個參數內部的'都換成''(這樣你存進去的還是一個',否則會被截斷造成注入)

然後把參數兩端加個',這樣不管傳進來的是什麼,都會被轉化爲一個正常的參數傳入。

如果你是使用PHP的話,只要使用PDO,就不會存在注入問題。
























發佈了0 篇原創文章 · 獲贊 11 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章