SQL是一種代碼注入技術,可使攻擊者修改應用程序向數據庫提供的查詢。 迄今為止,最常見和最嚴重的應用 程序安全威脅總是隱藏在與數據庫有某些連接的網絡應用 程序中。 通過這種 SQL 注入,攻擊者可以繞過登錄程序,獲取、更改甚至更新數據庫,執行管理程序,或進行其他變種操作。
了解 SQL 注入
要解釋什么 是 SQL 注入,就必須了解 SQL 的一些基本原理。 事實上,它已成為處理和虛擬操作這些數據庫的通用語言。 它用于查詢、插入、更新和刪除數據庫記錄,幾乎所有網絡應用程序都使用它來訪問數據庫;它可以在 PHP、 Python、 Java、 PIA Utah VPN 和 . NET中編寫 。
在網絡應用程序中,用戶需要通過表單、搜索框或 URL 等方式在系統中輸入信息,所有這些輸入信息通常都用于動態構建 SQL 查詢。 這是因為,如果用戶輸入的 SQL 查詢字符串沒有經過適當的檢查和消毒,攻擊者就可以通過在預期的 SQL 查詢字符串中注入惡意 SQL 語句來改變 SQL 查詢字符串的性質。
SQL 注入示例
舉例來說,在登錄一個典型的網絡應用程序時,用戶需要輸入用戶名和密碼。 用來驗證憑據的實際 SQL 查詢如下:
SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input';
如果應用程序直接使用用戶的輸入值而不進行任何消毒處理,攻擊者就可以輸入類似這樣的內容。
- 用戶名:
' OR '1'='1
- 密碼:
' OR '1'='1
由此產生的 SQL 查詢將是
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '' OR '1'='1';
這樣,攻擊者就能繞過驗證碼,暢通無阻地訪問系統
大家看這段代碼,其實特別簡單,就是我在沒有賬號和密碼的時候,用這段代碼來打開數據庫,這樣如果彈出“已經被sql注入” ,那么就代表我通過代碼層的注入。
大家一眼就可以看出來我的用戶名是1’ or ‘1’='1 密碼也是,結果是_:_
那么說明了,你的數據庫危險了,因為這個用戶名和密碼根本不存在。
那么這就是一個簡單的后臺身份驗證繞過了漏洞。
驗證繞過漏洞就是’or’='or’后臺繞過漏洞,利用的就是AND和OR的運算規則,從而造成后臺腳本邏輯性錯誤。
后臺查詢語句是: sql=‘select admin from user_info where userid=’ ‘’ & txtuser.text & ‘’’ & ’ and pwd=’ & ‘’’ & txtpassword.text & ‘’', 那么我使用1’or ‘1’='1(這里1可是其他的一些數)來做用戶名密碼的話,那么查詢就變成了: select admin from user_info where userid='1’or ‘1’=‘1’ and pwd='1’or ‘1’=‘1’
這樣的話,根據運算規則,這里一共有4個查詢語句,那么查詢結果就是 假or真and假or真,先算and 再算or,最終結果為真,這樣就可以進到后臺了。
這種漏洞存在必須要有2個致命的條件。
我們可以從這里入手,進行防護。
阻止 SQL 注入的方法
第一種:這種查詢是賬號和密碼是在一個sql語句中,如果一旦分開就不會被注入。
sql=“select * from admin where username='”&username&‘&"passwd=’"&passwd&’
如果一旦賬號密碼是分開查詢的,先查帳號,再查密碼,這樣的話就沒有辦法了。
我解決的代碼時這樣的:
txtsql = “select * from user_Info where userid= '” & TxtUserName.Text & “'”
Set mrc = ExecuteSQL(txtsql, msgtext)
If mrc.EOF Then
MsgBox “沒有這個用戶,請重新輸入用戶名!”, vbOKOnly + vbExclamation, “警告”
TxtUserName.SetFocus
Else
If Trim(mrc.Fields(1)) = Trim(TxtPassword.Text) Then
OK = True
mrc.Close
Me.Hide
UserName = Trim(TxtUserName.Text)
Else
MsgBox “密碼錯誤,請重新輸入!”, vbOKOnly + vbExclamation, “警告”
TxtPassword.SetFocus
TxtPassword.Text = “”
End If
第二種方法:如果加密了,一旦被MD5加密或者其他加密方式加密的,那么密碼就不會是完整的,那么就不存在這樣的錯誤了。
如果一個用戶提供的字段并非一個強類型,或者沒有實施類型強制,就會發生這種形式的攻擊。當在一個SQL語句中使用一個數字字段時,如果程序員沒有檢查用戶輸入的合法性(是否為數字型)就會發生這種攻擊。例如:
statement := "SELECT * FROM user_info WHERE userid = " & id_text & “;”
從這個語句可以看出,id_text是一個與“userid”字段有關的數字。不過,如果終端用戶選擇一個字符串,就繞過了對轉義字符的需要。例如,將id_text設置為:1;DROP TABLE users,它會將“users”表從數據庫中刪除,SQL語句變成:SELECT * FROM User_Info WHERE UserID= 1;DROP TABLE users;好滴,那么你的數據庫就會遭受不可恢復的刪除。
第三種方法:那么我們就可以通過傳參的方法,來解決這中sql注入:
如果自己編寫防注代碼,一般是先定義一個函數,再在里面寫入要過濾的關鍵詞,如select ; “”;from;等,這些關鍵詞都是查詢語句最常用的詞語,一旦過濾了,那么用戶自己構造提交的數據就不會完整地參與數據庫的操作。
Function SafeRequest(ParaName,ParaType)
‘— 傳入參數 —
‘ParaName:參數名稱-字符型
‘ParaType:參數類型-數字型(1表示以上參數是數字,0表示以上參數為字符)
Dim ParaValue
ParaValue=Request(ParaName)
If ParaType=1 then
If not isNumeric(ParaValue) then
Response.write “參數” & ParaName & “必須為數字型!”
Response.end
End if
Else
ParaValue=replace(ParaValue,"’“,”’’")
End if
SafeRequest=ParaValue
End function
為防止 SQL 注入,您需要遵循編碼準則、正確管理數據庫并實施安全措施。以下是一些降低 SQL 注入風險的策略:
1.使用預處理語句(參數化查詢)
預處理語句確保用戶輸入純粹作為數據處理,而不是作為 SQL 命令的組成部分。
這種方法允許數據庫區分 SQL 查詢結構和數據本身,確保任何輸入都不能修改查詢結構。
例如,在 PHP 中使用 PDO(PHP 數據對象):
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username AND password = :password');<br>
$stmt->execute(['username' => $username_input, 'password' => $password_input]);
在本例中,:username
和:password
是用戶輸入的占位符,它們會被用戶提供的實際值安全地替代。數據庫引擎將輸入作為純數據處理,因此任何惡意輸入都不會造成危害。
2.輸入驗證和消毒
始終對用戶輸入進行驗證和消毒,確保其符合預期格式。例如,如果輸入應該是一個整數,那么在處理之前就應該檢查數據類型。
在 Python 中,您可能會使用正則表達式來驗證輸入:
import re<br>
<br>
def validate_input(user_input):<br>if re.match("^[a-zA-Z0-9_]+$", user_input):<br>return True<br>else:<br>return False
該功能只允許使用字母數字字符和下劃線,從而降低了 SQL 注入的風險。
3.使用 ORM(對象關系映射)庫
ORM 庫抽象了數據庫交互,允許開發人員使用編程語言語法與數據庫交互,而不是直接使用 SQL 查詢。
通過自動安全地處理查詢構造,這一抽象本質上可防止 SQL 注入。
例如,在Django(一種 Python 網絡框架)中,你不需要編寫原始 SQL,而是像這樣與數據庫交互:
user = User.objects.get(username=user_input)
Django 的 ORM 可自動處理查詢結構并防止 SQL 注入。
4.限制數據庫權限
只授予應用程序必要的最低數據庫權限。如果應用程序不需要刪除記錄,就不要授予它DELETE
權限。這種最小權限原則可以減少攻擊者發現 SQL 注入漏洞時造成的破壞。
5.使用網絡應用防火墻(WAF)
WAF 可以在惡意輸入到達應用程序之前將其過濾掉,從而檢測并阻止常見的 SQL 注入嘗試。WAF 是一個額外的安全層,是對編碼實踐的補充。
6.錯誤處理和報告
避免向最終用戶顯示詳細的數據庫錯誤信息。相反,在服務器端記錄這些錯誤,并向用戶顯示通用錯誤信息。這種做法可以防止攻擊者深入了解你的數據庫結構。
在 .NET 中,您可以使用 try-catch 塊來處理 SQL 錯誤:
try<br>
{<br>// Database operations<br>
}<br>
catch (SqlException ex)<br>
{<br>// Log error details<br>Logger.Log(ex);<br>// Show a generic message to the user<br>Response.Write("An error occurred. Please try again later.");<br>