SQL注入的風險與解決方案實戰(zhàn)解析
前言
在日常開發(fā)中,數(shù)據(jù)庫操作幾乎是繞不開的環(huán)節(jié)。很多同學寫查詢語句的時候,習慣直接用字符串拼接,比如:
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
乍一看挺正常,但一旦碰上心懷不軌的攻擊者,后果就可能非常嚴重。這就是我們常說的 SQL 注入 問題。
什么是 SQL 注入
SQL 注入的本質(zhì)就是:
用戶的輸入被直接拼接到 SQL 語句中,沒有做任何防護,導致數(shù)據(jù)庫把攻擊者的輸入當成真正的 SQL 指令去執(zhí)行。
舉個最經(jīng)典的例子:
如果登錄接口這樣寫:
String username = "admin"; String password = "' OR '1'='1"; // 攻擊者輸入的內(nèi)容 String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'"; System.out.println(sql);
拼接后的 SQL 就變成了:
SELECT * FROM users WHERE username='admin' AND password='' OR '1'='1'
這一句 OR '1'='1' 永遠成立,所以攻擊者輕輕松松繞過了密碼驗證,直接登錄成功。
真實場景下的危害
別以為這只是理論,現(xiàn)實中因為 SQL 注入出問題的案例太多了。常見危害包括:
- 繞過身份認證:像上面的例子,用戶不用知道密碼也能登錄。
- 數(shù)據(jù)泄露:攻擊者可以拼接語句,把整個表的數(shù)據(jù)都查詢出來。
- 數(shù)據(jù)篡改或刪除:嚴重的情況下,甚至可以執(zhí)行
DROP TABLE users;直接把表刪掉。 - 權(quán)限提升:通過復雜的注入方式,攻擊者可能拿到數(shù)據(jù)庫更高權(quán)限,導致系統(tǒng)全面失控。
所以在企業(yè)開發(fā)里,SQL 注入算是基礎(chǔ)中的基礎(chǔ),必須提前預防。
常見解決方案
那我們該怎么防范呢?有幾種常見的方式:
1. 使用 PreparedStatement
PreparedStatement 是 JDBC 提供的預編譯語句對象。它會先把 SQL 模板交給數(shù)據(jù)庫編譯好,然后再傳入?yún)?shù)。這樣參數(shù)和 SQL 邏輯嚴格分離,用戶輸入就不會被當成 SQL 指令執(zhí)行。
Demo 代碼:
import java.sql.*;
public class SafeLoginDemo {
public static void main(String[] args) throws Exception {
String url = "jdbc:mysql://localhost:3306/testdb";
String user = "root";
String pass = "123456";
String inputUser = "admin";
String inputPass = "' OR '1'='1";
Connection conn = DriverManager.getConnection(url, user, pass);
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, inputUser);
stmt.setString(2, inputPass);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
System.out.println("登錄成功: " + rs.getString("username"));
} else {
System.out.println("用戶名或密碼錯誤");
}
rs.close();
stmt.close();
conn.close();
}
}
這里無論用戶輸入什么奇怪的密碼,數(shù)據(jù)庫都會把它當成一個普通的字符串參數(shù)處理,而不是 SQL 邏輯。
2. MyBatis 使用#{}占位符
在 MyBatis 中,有兩個寫法經(jīng)常被混淆:${} 和 #{}。
${}:直接拼接字符串,可能導致 SQL 注入。#{}:安全的參數(shù)綁定,底層會幫你用 PreparedStatement。
錯誤寫法(容易被注入):
<select id="getUserByName" resultType="User">
SELECT * FROM users WHERE username = '${username}'
</select>
正確寫法(推薦使用):
<select id="getUserByName" resultType="User">
SELECT * FROM users WHERE username = #{username}
</select>
這樣就算有人傳了 ' OR '1'='1 這樣的輸入,也只會作為字符串參數(shù)傳入,不會破壞 SQL 邏輯。
3. 使用 ORM 框架封裝查詢
像 Hibernate、JPA 這類 ORM 框架,通常都已經(jīng)封裝了參數(shù)綁定邏輯,默認情況下就能避免注入風險。
比如用 Spring Data JPA:
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsernameAndPassword(String username, String password);
}
Spring Data JPA 底層會自動生成類似 PreparedStatement 的語句,所以基本不需要擔心 SQL 注入問題。
總結(jié)
回過頭來看,SQL 注入的核心原因是 “把用戶輸入當成 SQL 語句的一部分”。
解決的思路就是 “參數(shù)化查詢”,讓 SQL 和用戶輸入嚴格分離。
落地建議:
- 在 JDBC 層,統(tǒng)一用
PreparedStatement。 - 在 MyBatis 中,統(tǒng)一用
#{}而不是${}。 - 在使用 ORM 框架時,不要為了圖省事拼接 JPQL/HQL。
- 養(yǎng)成安全開發(fā)習慣,做代碼審查時重點關(guān)注數(shù)據(jù)庫查詢部分。
到此這篇關(guān)于SQL注入的風險與解決方案實戰(zhàn)解析的文章就介紹到這了,更多相關(guān)SQL注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
通過存儲過程動態(tài)創(chuàng)建MySQL對象的流程步驟
在當今數(shù)據(jù)驅(qū)動的世界中,高效的數(shù)據(jù)庫管理至關(guān)重要,本文將展示如何通過存儲過程自動化地創(chuàng)建各種?MySQL?數(shù)據(jù)庫對象,通過這些方法,我們可以快速響應業(yè)務需求,提高數(shù)據(jù)庫管理的靈活性和效率,需要的朋友可以參考下2024-10-10
詳解CentOS 6.5中安裝mysql 5.7.16 linux glibc2.5 x86 64(推薦)
這篇文章主要介紹了CentOS 6.5中安裝mysql 5.7.16 linux glibc2.5 x86 64(推薦)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12
開源MySQL高效數(shù)據(jù)倉庫解決方案:Infobright詳細介紹
這篇文章主要介紹了開源MySQL高效數(shù)據(jù)倉庫解決方案:Infobright詳細介紹,本文講解了Infobright特征、Infobright的價值、Infobright的適用場景、與MySQL對比等內(nèi)容,需要的朋友可以參考下2015-03-03
MySQL數(shù)據(jù)庫高級數(shù)據(jù)操作之新增數(shù)據(jù)
這篇文章主要介紹了MySQL數(shù)據(jù)庫高級數(shù)據(jù)操作之新增數(shù)據(jù),文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-06-06
詳解mysql中字符串轉(zhuǎn)為數(shù)字的三種方法
這篇文章主要為大家詳細介紹了mysql中字符串轉(zhuǎn)為數(shù)字的三種常用方法,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學習一下2023-11-11
解決大于5.7版本mysql的分組報錯Expression #1 of SELECT list is not in GR
這篇文章主要介紹了解決大于5.7版本mysql的分組報錯Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated問題,需要的朋友可以參考下2019-10-10

