sql注入的方法以及如何防止sql注入
我是艾西,從業多年的IDC伺服器機房行業總是會遇到各種各樣的網絡漏洞以及鬥智鬥勇的過程,今天和大家聊聊sql注入的方法以及如何防止sql注入
SQL 注入(SQL Injection)是發生在 Web 程式中資料庫層的安全漏洞,是網站存在最多也是最簡單的漏洞。主要原因是程式對使用者輸入資料的合法性沒有判斷和處理,導緻攻擊者可以在 Web 應用程式中事先定義好的 SQL 語句中添加額外的 SQL 語句,在管理者不知情的情況下實作非法操作,以此來實作欺騙資料庫伺服器執行非授權的任意查詢,進而進一步擷取到資料資訊。
簡而言之,SQL 注入就是在使用者輸入的字元串中加入 SQL 語句,如果在設計不良的程式中忽略了檢查,那麼這些注入進去的 SQL 語句就會被資料庫伺服器誤認為是正常的 SQL 語句而運作,攻擊者就可以執行計劃外的指令或通路未被授權的資料。
SQL 注入已經成為網際網路世界 Web 應用程式的最大風險,我們有必要從開發、測試、上線等各個環節對其進行防範。下面介紹 SQL 注入的原理及避免 SQL 注入的一些方法。
SQL注入的原理
SQL 注入的原理主要有以下 4 點:
1)惡意拼接查詢
我們知道,SQL 語句可以查詢、插入、更新和删除資料,且使用分号來分隔不同的指令。例如:
SELECT * FROM users WHERE user_id = $user_id
其中,user_id 是傳入的參數,如果傳入的參數值為“1234; DELETE FROM users”,那麼最終的查詢語句會變為:
SELECT * FROM users WHERE user_id = 1234; DELETE FROM users
如果以上語句執行,則會删除 users 表中的所有資料。
2)利用注釋執行非法指令。
SQL 語句中可以插入注釋。例如:
SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version=$version
如果 version 包含了惡意的字元串'-1' OR 3 AND SLEEP(500)--,那麼最終查詢語句會變為:
SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version='-1' OR 3 AND SLEEP(500)--
以上惡意查詢隻是想耗盡系統資源,SLEEP(500) 将導緻 SQL 語句一直運作。如果其中添加了修改、删除資料的惡意指令,那麼将會造成更大的破壞。
3)傳入非法參數
SQL 語句中傳入的字元串參數是用單引号引起來的,如果字元串本身包含單引号而沒有被處理,那麼可能會篡改原本 SQL 語句的作用。 例如:
SELECT * FROM user_name WHERE user_name = $user_name
如果 user_name 傳入參數值為 G'chen,那麼最終的查詢語句會變為:
SELECT * FROM user_name WHERE user_name ='G'chen'
一般情況下,以上語句會執行出錯,這樣的語句風險比較小。雖然沒有文法錯誤,但可能會惡意産生 SQL 語句,并且以一種你不期望的方式運作。
4)添加額外條件
在 SQL 語句中添加一些額外條件,以此來改變執行行為。條件一般為真值表達式。例如:
UPDATE users SET userpass='$userpass' WHERE user_id=$user_id;
如果 user_id 被傳入惡意的字元串“1234 OR TRUE”,那麼最終的 SQL 語句會變為:
UPDATE users SET userpass= '123456' WHERE user_id=1234 OR TRUE;
這将更改所有使用者的密碼。
SQL注入:通過在Web表單中插入SQL指令送出或輸入域名或頁面請求的查詢字元串來欺騙伺服器執行惡意SQL指令。
具體來說,就是利用現有應用程式将(惡意)SQL指令注入到背景資料庫引擎執行中的能力,可以通過在Web表單中輸入(惡意)SQL語句來擷取安全漏洞網站上的資料庫,而不是按照設計者的意圖執行 SQL 語句。例如,以往的很多影視網站洩露VIP會員密碼的方式大多是通過WEB表單送出查詢字元
網站頁面包含與資料庫互動的部分(如新聞網站的搜尋功能),當在網站上輸入資料資訊時,将資料資訊程式設計并傳遞給執行的資料庫。對傳入資料庫的相應資料進行安全處理(如過濾特殊字元、編碼等),使黑客可以通過網站并在資料庫中執行它們。這些以黑客為目的的SQL語句會導緻資料庫資訊的洩露和破壞。
1、數字注入點
很多網頁連結都有類似的結構 http://www.XXX.com/123456.php?id=1 基于這種形式的注入,一般稱為數字注入點,因為它的注入點 id 類型是一個數字。在大部分網頁中,比如檢視使用者個人資訊、檢視文章等,大多采用這種結構形式來傳遞id等資訊,交給後端,在資料庫中查詢相應的資訊,然後傳回到前台。這類SQL語句的原型大概是select * from table name where id=1 如果有注入,我們可以構造類似下面的SQL注入語句進行爆破: select * from table name where id=1 and 1= 1
2、字元注入點
網頁連結結構類似 http://www.XXX.com/users.php?user=admin 在這種形式中,注入點的使用者類型是字元類型,是以稱為字元注入觀點。這類 SQL 語句的原型大概是 select * from table name where user='admin'。值得注意的是,這裡的引号比數值注入類型的SQL語句原型要多,可以是單引号,也可以是雙引号。如果有注入,我們可以構造類似如下的sql注入語句進行爆破: select * from table name where user='admin' and 1=1 ' 我們需要處理這些煩人的引号。
3、搜尋注入點
這是一種特殊類型的注入。這類注入主要是指在資料搜尋時不過濾搜尋參數。一般連結位址中有“keyword=keyword”,有的連結位址不顯示,而是直接通過搜尋框表單送出。此類注入點送出的SQL語句的原始形式大緻為:select * from table name where field like '%keyword%' 如果有注入,我們可以構造類似如下的SQL注入語句進行爆破:select * 來自表名稱,其中字段如 '%test%' 和 '%1%'='%1%'
隻要所有輸入都與資料庫互動,就可能觸發 SQL 注入。 SQL注入可分為:按資料送出方式:
(1)GET注入:送出資料的方法是GET,注入點的位置在GET參數部分。比如有這樣一個連結http://xxx.com/ news.php?id=1 ,id為注入點。
(2)POST注入:使用POST方式送出資料,注入點位于POST資料部分,經常出現在表單中。
(3)Cookie注入:用戶端的cookie會包含在HTTP請求中,注入點存在于cookie中的某個字段中。
(4)HTTP頭注入:注入點在HTTP請求頭中的一個字段中。例如存在于User-Agent字段中。嚴格來說cookies也應該被認為是一種header注入.form.因為在HTTP請求中,Cookie是header中的一個字段。
按照送出方式分類後,你會發現SQL注入最長出現在連結位址、資料參數、cookie資訊和HTTP請求頭中。
了解SQL注入的可能位置,然後我們需要判斷這些位置是否可以觸發SQL注入。最簡單的方法是在對應的位置輸入and 1=1(和and 1=1的變換形式)來判斷。對于不同的注入點類型,比如字元類型,需要适當加單引号,而對于數字類型的注入點,則不需要。
SQL注入進階分類(按執行效果分類)
1、基于布爾的盲注:即可以根據傳回的頁面判斷條件真假的注入。
2、基于時間的盲注:即不能根據頁面傳回的内容判斷任何資訊,使用條件語句檢查是否執行了延時語句(即頁面傳回時間是否增加)。
3、基于錯誤注入:即頁面會傳回錯誤資訊,或者注入語句的結果直接傳回給頁面。
4、聯合查詢注入:聯合可用時注入。
5、堆查詢注入:可以同時執行多條語句的注入。
6、寬位元組注入:使用gbk是多位元組編碼,兩個位元組代表一個漢字
避免SQL注入
對于 SQL 注入,我們可以采取适當的預防措施來保護資料安全。下面是避免 SQL 注入的一些方法。
1. 過濾輸入内容,校驗字元串
過濾輸入内容就是在資料送出到資料庫之前,就把使用者輸入中的不合法字元剔除掉。可以使用程式設計語言提供的處理函數或自己的處理函數來進行過濾,還可以使用正規表達式比對安全的字元串。
如果值屬于特定的類型或有具體的格式,那麼在拼接 SQL 語句之前就要進行校驗,驗證其有效性。比如對于某個傳入的值,如果可以确定是整型,則要判斷它是否為整型,在浏覽器端(用戶端)和伺服器端都需要進行驗證。
2. 參數化查詢
參數化查詢目前被視作是預防 SQL 注入攻擊最有效的方法。參數化查詢是指在設計與資料庫連接配接并通路資料時,在需要填入數值或資料的地方,使用參數(Parameter)來給值。
MySQL 的參數格式是以“?”字元加上參數名稱而成,如下所示:
UPDATE myTable SET c1 = ?c1, c2 = ?c2, c3 = ?c3 WHERE c4 = ?c4
在使用參數化查詢的情況下,資料庫伺服器不會将參數的内容視為 SQL 語句的一部分來進行處理,而是在資料庫完成 SQL 語句的編譯之後,才套用參數運作。是以就算參數中含有破壞性的指令,也不會被資料庫所運作。
3. 安全測試、安全審計
除了開發規範,還需要合适的工具來確定代碼的安全。我們應該在開發過程中應對代碼進行審查,在測試環節使用工具進行掃描,上線後定期掃描安全漏洞。通過多個環節的檢查,一般是可以避免 SQL 注入的。
有些人認為存儲過程可以避免 SQL 注入,存儲過程在傳統行業裡用得比較多,對于權限的控制是有一定用處的,但如果存儲過程用到了動态查詢,拼接 SQL,一樣會存在安全隐患。
下面是在開發過程中可以避免 SQL 注入的一些方法。
1. 避免使用動态SQL
避免将使用者的輸入資料直接放入 SQL 語句中,最好使用準備好的語句和參數化查詢,這樣更安全。
2. 不要将敏感資料保留在純文字中
加密存儲在資料庫中的私有/機密資料,這樣可以提供了另一級保護,以防攻擊者成功地排出敏感資料。
3. 限制資料庫權限和特權
将資料庫使用者的功能設定為最低要求;這将限制攻擊者在設法擷取通路權限時可以執行的操作。
4. 避免直接向使用者顯示資料庫錯誤
攻擊者可以使用這些錯誤消息來擷取有關資料庫的資訊。
一些程式設計架構對于寫出更安全的代碼也有一定的幫助,因為它提供了一些處理字元串的函數和使用查詢參數的方法。但同樣,你仍然可以編寫出不安全的 SQL 語句。是以歸根到底,我們需要有良好的編碼規範,并能充分利用參數化查詢、字元串處理和參數校驗等多種辦法來保護資料庫和程式的安全。
1.嚴格區分使用者權限
在權限設計中,針對軟體使用者,沒有必要給予資料庫的建立、删除等管理權限。這樣即便在使用者輸入的SQL語句種含有内嵌式的惡意程式,因為其權限的限定,也不可能執行。是以程式在權限設計時,最好把管理者與使用者差別起來。這樣能夠最大限度的降低注入式攻擊對資料庫産生的損害。
2、強制使用參數化語句。
如果使用者輸入的變量在編寫SQL語句時沒有直接嵌入到SQL語句中。如果将此變量通過參數傳遞,則可以有效防止 SQL 注入攻擊。也就是說,使用者的輸入不能直接嵌入到 SQL 語句中。相反,必須過濾使用者輸入,或者必須使用參數化語句來傳遞使用者輸入變量。參數化語句使用參數而不是将使用者輸入變量嵌入到 SQL 語句中。使用這種措施可以防止大部分的 SQL 注入攻擊。不幸的是,支援參數化語句的資料庫引擎并不多。但是,資料庫工程師在開發産品時應該盡量使用參數化語句。
3、使用 SQL Server 資料庫附帶的安全參數。
為了減少注入攻擊對SQL Server資料庫的不利影響,在SQL Server資料庫中專門設計了相對安全的SQL參數。在資料庫設計過程中,工程師應該盡量利用這些參數來防止惡意SQL注入攻擊。
Parameters 集合在 SQL Server 資料庫中提供。此集合提供類型檢查和長度驗證。如果管理者使用Parameters集合,使用者輸入将被視為字元值而不是可執行代碼。即使使用者輸入包含可執行代碼,資料庫也會将其過濾掉。因為此時資料庫隻将其視為普通字元。使用Parameters集合的另一個好處是可以強制執行類型和長度檢查,超出範圍的值會觸發異常。如果使用者輸入的值不滿足指定的類型和長度限制,則會引發異常并報告給管理者。如上例,如果員工編号定義的資料類型為字元串,則長度為10個字元。使用者輸入的内容也是字元型資料,但長度達到20個字元。此時會抛出異常,因為使用者輸入的内容長度超過了資料庫字段長度的限制。
4、增強的使用者輸入驗證。
一般來說,可以使用兩種方法來防止 SQL 注入攻擊。一是加強對使用者輸入内容的檢查和驗證;另一種是強制使用參數化語句來傳遞使用者輸入的内容。在 SQL Server 資料庫中,有很多使用者輸入内容驗證工具,可以幫助管理者應對 SQL 注入攻擊。測試字元串變量的内容,隻接受所需的值。拒絕包含二進制資料、轉義序列和注釋字元的輸入。這有助于防止腳本注入,防止一些緩沖區溢出攻擊。測試使用者輸入的大小和資料類型,實施适當的限制和轉換。這有助于防止故意的緩沖區溢出,對防止注入攻擊有比較明顯的效果。
例如,存儲過程可用于驗證使用者輸入。使用存儲過程可以過濾使用者輸入的變量,比如拒絕一些特殊的符号。比如上面的惡意代碼,隻要存儲過程過濾掉分号,惡意代碼就沒用了。在執行 SQL 語句之前,可以通過資料庫的存儲過程拒絕接受一些特殊符号。在不影響資料庫應用的前提下,應使資料庫拒絕包含以下字元的輸入。和分号分隔符一樣,是SQL注入攻擊的主要幫兇。例如注釋分隔符。注釋僅在資料設計期間使用。一般使用者的查詢語句中沒有必要的注釋内容,直接拒絕即可。通常,這樣做不會有意外損失。如果這些特殊符号被拒絕,即使 SQL 語句中嵌入了惡意代碼,它們也不會做任何事情。
是以,請始終通過測試類型、長度、格式和範圍來驗證使用者輸入,并過濾使用者輸入。這是防止 SQL 注入攻擊的常用且行之有效的措施。
5、如何防範多層環境下的SQL注入攻擊?
在多層應用環境中,使用者輸入的所有資料在被允許進入可信區域之前都應該經過身份驗證。驗證過程失敗的資料應被資料庫拒絕,并向上層傳回錯誤消息。實施多層身份驗證。對沒有目的的惡意使用者采取的預防措施可能對堅定的攻擊者無效。更好的做法是在使用者界面和跨信任邊界的所有後續點驗證輸入。例如,驗證用戶端應用程式中的資料可以防止簡單的腳本注入。但是,如果下一層認為其輸入已經過驗證,則任何可以繞過用戶端的惡意使用者都可以不受限制地通路系統。是以,對于多層應用環境,在防範注入攻擊時,需要各層協同工作,用戶端和資料庫端都必須采取相應的措施來防範SQL語句注入攻擊。
5.利用陷阱賬戶
可以設定兩個賬戶,即管理者賬戶和防注入賬戶。将防注入的賬戶僞裝成管理者賬戶,如将名稱設定為admin,讓檢測軟體産生錯覺,在密碼方面,可以設定成超長的中文字元(幾千字),讓攻擊者的漏洞檢測軟體達到高負荷狀态直至資源耗盡。
我是艾西,今天的分享就到這裡啦。
攜手馳網為您網絡的道路上保駕護航