更新時間:2022-04-25 09:57:19 來源:動力節(jié)點 瀏覽877次
SQL注入是一種注入攻擊。當攻擊者提交惡意制作的輸入時,就會發(fā)生注入攻擊,從而導致應用程序執(zhí)行意外操作。由于SQL數(shù)據(jù)庫無處不在,SQL 注入是互聯(lián)網(wǎng)上最常見的攻擊類型之一。
如果您只有時間保護自己免受一個漏洞的影響,那么您應該檢查代碼庫中的 SQL 注入漏洞!
當您遭受 SQL 注入攻擊時,可能發(fā)生的最糟糕的事情是什么?
我們的示例 hack向您展示了如何繞過登錄頁面:銀行網(wǎng)站的一個巨大安全漏洞。更復雜的攻擊將允許攻擊者在數(shù)據(jù)庫上運行任意語句。過去,黑客使用注入攻擊來:
提取敏感信息,例如社會安全號碼或信用卡詳細信息。
枚舉在網(wǎng)站上注冊的用戶的身份驗證詳細信息,因此這些登錄信息可用于對其他網(wǎng)站的攻擊。
刪除數(shù)據(jù)或刪除表,破壞數(shù)據(jù)庫,使網(wǎng)站無法使用。
當用戶訪問該站點時,注入要執(zhí)行的更多惡意代碼。
SQL 注入攻擊非常普遍。雅虎和索尼等大公司的應用程序受到了損害。在其他情況下,黑客組織針對 特定的應用程序或編寫旨在收集身份驗證詳細信息的腳本。即使是安全公司 也不能幸免!
所以 SQL 注入是一個嚴重的風險。你怎么能保護自己?
參數(shù)化語句
編程語言使用數(shù)據(jù)庫驅(qū)動程序與 SQL 數(shù)據(jù)庫對話。 驅(qū)動程序允許應用程序針對數(shù)據(jù)庫構(gòu)建和運行 SQL 語句,根據(jù)需要提取和操作數(shù)據(jù)。參數(shù)化語句確保傳遞給 SQL 語句的參數(shù)(即輸入)以安全的方式處理。
例如, 使用參數(shù)化語句在JDBC中運行 SQL 查詢的安全方法是:
// Connect to the database.
Connection conn = DriverManager.getConnection(URL, USER, PASS);
// Construct the SQL statement we want to run, specifying the parameter.
String sql = "SELECT * FROM users WHERE email = ?";
// Generate a prepared statement with the placeholder parameter.
PreparedStatement stmt = conn.prepareStatement(sql);
// Bind email value into the statement at parameter index 1.
stmt.setString(1, email);
// Run the query...
ResultSet results = stmt.executeQuery(sql);
while (results.next())
{
// ...do something with the data returned.
}
將此與 SQL 字符串的顯式構(gòu)造進行對比,后者非常非常危險:
// The user we want to find.
String email = "user@email.com";
// Connect to the database.
Connection conn = DriverManager.getConnection(URL, USER, PASS);
Statement stmt = conn.createStatement();
// Bad, bad news! Don't construct the query with string concatenation.
String sql = "SELECT * FROM users WHERE email = '" + email + "'";
// I have a bad feeling about this...
ResultSet results = stmt.executeQuery(sql);
while (results.next()) {
// ...oh look, we got hacked.
}
關(guān)鍵區(qū)別在于傳遞給executeQuery(...) 方法的數(shù)據(jù)。在第一種情況下,參數(shù)化字符串和參數(shù)分別傳遞給數(shù)據(jù)庫,這允許驅(qū)動程序正確解釋它們。在第二種情況下,完整的 SQL 語句是在調(diào)用驅(qū)動程序之前構(gòu)建的,這意味著我們?nèi)菀资艿綈阂庵谱鞯膮?shù)的攻擊。
您應該始終在可用的情況下使用參數(shù)化語句,它們是防止 SQL 注入的第一保護。
您可以在下面的代碼示例中看到更多不同語言的參數(shù)化語句示例。
許多開發(fā)團隊更喜歡使用對象關(guān)系映射 (ORM) 框架來使 SQL 結(jié)果集到代碼對象的轉(zhuǎn)換更加無縫。ORM 工具通常意味著開發(fā)人員很少需要在他們的代碼中編寫 SQL 語句——幸運的是,這些工具在后臺使用了參數(shù)化語句。
最著名的 ORM 可能是 Ruby on Rails 的Active Record框架。使用 Active Record 從數(shù)據(jù)庫中獲取數(shù)據(jù)如下所示:
def current_user(email)
# The 'User' object is an Active Record object, that has find methods
# auto-magically generated by Rails.
User.find_by_email(email)
end
像這樣的代碼可以免受 SQL 注入攻擊。
然而,使用 ORM 并不會自動讓您免受 SQL 注入的影響。 當需要對數(shù)據(jù)庫執(zhí)行更復雜的操作時,許多 ORM 框架允許您構(gòu)造 SQL 語句或 SQL 語句的片段。例如,以下 Ruby 代碼容易受到注入攻擊:
def current_user(email)
# This code would be vulnerable to a maliciously crafted email parameter.
User.where("email = '" + email + "'")
end
作為一般經(jīng)驗法則:如果您發(fā)現(xiàn)自己通過連接字符串來編寫 SQL 語句,請仔細考慮您在做什么。
如果您無法使用參數(shù)化語句或為您編寫 SQL 的庫,則下一個最佳方法是確保正確轉(zhuǎn)義輸入?yún)?shù)中的特殊字符串字符。
注入攻擊通常依賴于攻擊者能夠制作一個輸入,該輸入將過早關(guān)閉它們出現(xiàn)在 SQL 語句中的參數(shù)字符串。(這就是為什么您經(jīng)常會在嘗試的 SQL 注入攻擊中看到'或字符的原因。)"
編程語言有標準的方法來描述其中包含引號的字符串——SQL 在這方面沒有什么不同。通常,將引號字符加倍——替換'為''——意味著 “將此引號視為字符串的一部分,而不是字符串的結(jié)尾”。
轉(zhuǎn)義符號字符是防止大多數(shù) SQL 注入攻擊的簡單方法,許多語言都有標準函數(shù) 來實現(xiàn)這一點。但是,這種方法有幾個缺點:
您需要非常小心地在構(gòu)建 SQL 語句的代碼庫中的任何地方轉(zhuǎn)義字符。
并非所有注入攻擊都依賴于引用字符的濫用。 例如,當 SQL 語句中需要數(shù)字 ID 時,不需要引號字符。無論您如何使用引號字符,以下代碼仍然容易受到注入攻擊:
def current_user(id)
User.where("id = " + id)
end
清理輸入是所有應用程序的好習慣。在我們的 示例 hack中,用戶提供了一個密碼 as ' or 1=1--,這看起來很可疑作為密碼選擇。
開發(fā)人員應始終努力拒絕看起來可疑的輸入,同時注意不要意外懲罰合法用戶。例如,您的應用程序可以通過以下方式清除GET 和POST請求中提供的參數(shù):
檢查提供的字段(如電子郵件地址)是否與正則表達式匹配。
確保數(shù)字或字母數(shù)字字段不包含符號字符。
在不合適的地方拒絕(或去除)空格和換行符。
客戶端驗證(即在 JavaScript 中)對于在填寫表單時為用戶提供即時反饋很有用,但不能防御嚴重的黑客。大多數(shù)黑客嘗試都是使用腳本執(zhí)行的,而不是瀏覽器本身。