轉載::
常見攻擊方式
一般說來,在Web安全領域,常見的攻擊方式大概有以下幾種:
1、SQL注入攻擊
2、跨站腳本攻擊 - XSS
3、跨站僞造請求攻擊 - CSRF
4、文件上傳漏洞攻擊
5、分佈式拒絕服務攻擊 - DDOS
SQL注入產生的原因,和棧溢出、XSS等很多其他的攻擊方法類似,就是未經檢查或者未經充分檢查的用戶輸入數據,意外變成了代碼被執行。也就是,SQL注入是用戶輸入的數據,在拼接SQL語句的過程中,超越了數據本身,成爲了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注入漏洞呢?一般說來有以下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參數進行注入。
1、對於服務器配置層面的防範,應該保證生產環境的Webserver是關閉錯誤信息的,比如PHP在生產環境的配置文件php.ini中的display_errors應該設置爲Off,這樣就關閉了錯誤提示,下面我們更多的從編碼的角度來看看如何防範SQL注入。
如果你的SQL語句是類似where id={$id}這種形式,數據庫裏所有的id都是數字,那麼就應該在SQL被執行前,檢查確保變量id是int類型;如果是接受郵箱,那就應該檢查並嚴格確保變量一定是郵箱的格式,其他的類型比如日期、時間等也是一個道理。總結起來:只要是有固定格式的變量,在SQL語句執行前,應該嚴格按照固定格式去檢查,確保變量是我們預想的格式,這樣很大程度上可以避免SQL注入攻擊。
對於無法確定固定格式的變量,一定要進行特殊符號過濾或轉義處理。以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}";
從上面可以看出,第二個SQL語句是有漏洞的,不過由於使用了addslashes函數,你會發現黑客的攻擊語句也存在不能使用特殊符號的條件限制,類似where username='plhwin'這樣的攻擊語句是沒法執行的,但是黑客可以將字符串轉爲16進制編碼數據或使用char函數進行轉化,同樣能達到相同的目的,如果對這部分內容感興趣,可以(http://cbb.sjtu.edu.cn/course/database/lab8.htm)這裏查看。而且由於SQL保留關鍵字,如「HAVING」、「ORDER BY」的存在,即使是基於黑白名單的過濾方法仍然會有或多或少問題,那麼是否還有其他方法來防禦SQL注入呢?
3、綁定變量,使用預編譯語句
在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、認真檢查是否存在例外
備份很重要,即使發生這類悲劇,通過上一次備份重建數據庫和重放最近更新來挽救
時隔很久看自己發的都感覺搞笑,目前我是這樣做的:
把每一個參數內部的'都換成''(這樣你存進去的還是一個',否則會被截斷造成注入)
然後把參數兩端加個',這樣不管傳進來的是什麼,都會被轉化爲一個正常的參數傳入。
如果你是使用PHP的話,只要使用PDO,就不會存在注入問題。