Java預防SQL注入的具體實踐方法
1. 強制使用 PreparedStatement(參數(shù)化查詢)
原理:將 SQL 語句結(jié)構(gòu)與用戶輸入數(shù)據(jù)分離,確保輸入內(nèi)容始終作為“數(shù)據(jù)”處理,而非可執(zhí)行的代碼。
正確示例:
String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, username); // 自動轉(zhuǎn)義特殊字符(如 ' -> \') pstmt.setString(2, password); try (ResultSet rs = pstmt.executeQuery()) { // 處理結(jié)果 } }
錯誤做法(高危?。?/h3>
// 直接拼接 SQL(存在注入風險?。?
String sql = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// 直接拼接 SQL(存在注入風險?。? String sql = "SELECT * FROM users WHERE username = '" + username + "'"; Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql);
2. 使用 ORM 框架(如 Hibernate/JPA)
ORM 框架會自動生成參數(shù)化查詢,減少手寫 SQL 的注入風險。
Hibernate 示例:
// 使用 Hibernate Criteria API CriteriaBuilder cb = session.getCriteriaBuilder(); CriteriaQuery<User> query = cb.createQuery(User.class); Root<User> root = query.from(User.class); query.where( cb.equal(root.get("username"), username), cb.equal(root.get("password"), password) ); User user = session.createQuery(query).uniqueResult();
HQL 參數(shù)化:
String hql = "FROM User WHERE username = :username"; Query<User> query = session.createQuery(hql, User.class); query.setParameter("username", username); User user = query.uniqueResult();
3. 輸入驗證與過濾
白名單校驗:
// 校驗用戶名是否符合規(guī)則(僅允許字母、數(shù)字、下劃線) if (!username.matches("^[a-zA-Z0-9_]{4,20}$")) { throw new IllegalArgumentException("Invalid username"); }
轉(zhuǎn)義特殊字符(備用方案):
如果必須拼接 SQL(如動態(tài)表名),需嚴格過濾:
// 使用 Apache Commons Text 轉(zhuǎn)義 String safeInput = StringEscapeUtils.escapeSql(input); // 僅適用于簡單場景,不推薦依賴!
4. 避免動態(tài)拼接 SQL
高危場景:動態(tài)表名、列名等無法通過 PreparedStatement
參數(shù)化。
安全做法:使用白名單校驗合法值:
// 動態(tài)表名校驗(只允許預定義的合法表名) Set<String> validTables = Set.of("users", "products"); if (!validTables.contains(tableName)) { throw new IllegalArgumentException("Invalid table name"); } String sql = "SELECT * FROM " + tableName; // 此時拼接是安全的
5. 數(shù)據(jù)庫配置與權限
最小權限原則:應用使用的數(shù)據(jù)庫賬號應僅擁有
SELECT
、INSERT
、UPDATE
等必要權限,禁止DROP
、GRANT
等高危操作。禁用敏感函數(shù):如 MySQL 的
LOAD_FILE
、INTO OUTFILE
。
6. 其他安全措施
隱藏錯誤信息:
try { // 執(zhí)行數(shù)據(jù)庫操作 } catch (SQLException e) { // 生產(chǎn)環(huán)境返回通用錯誤,避免泄露細節(jié) logger.error("Database error", e); throw new RuntimeException("Internal server error"); }
使用安全工具:
OWASP ESAPI:提供安全的 SQL 轉(zhuǎn)義方法。
SQL 注入掃描工具:集成
sqlmap
或SonarQube
進行代碼審計。
總結(jié):Java 防御 SQL 注入的核心規(guī)則
場景
安全做法
高風險做法(避免?。?/p>
執(zhí)行 SQL 查詢
使用 PreparedStatement
參數(shù)化
拼接字符串生成 SQL
動態(tài)表名/列名
白名單校驗合法值
直接拼接用戶輸入
輸入驗證
正則表達式白名單過濾
僅在前端驗證或不做驗證
錯誤信息處理
記錄日志,返回通用錯誤提示
返回詳細數(shù)據(jù)庫錯誤信息
ORM 框架
優(yōu)先使用 Hibernate/JPA 的 Criteria 或 HQL
手動拼接 HQL 或 JPQL
關鍵點:
絕不信任用戶輸入:所有外部輸入(包括 HTTP 請求參數(shù)、Cookie、Headers)均需驗證和轉(zhuǎn)義。
代碼審查:定期檢查項目中是否存在
Statement
或字符串拼接 SQL 的代碼。依賴更新:確保數(shù)據(jù)庫驅(qū)動和 ORM 框架保持最新版本,修復已知漏洞。
以上就是Java預防SQL注入的具體實踐方法的詳細內(nèi)容,更多關于Java預防SQL注入的資料請關注腳本之家其它相關文章!
相關文章
Java中String和StringBuffer及StringBuilder?有什么區(qū)別
這篇文章主要介紹了Java中String和StringBuffer及StringBuilder?有什么區(qū)別,String?是?Java?語言非?;A和重要的類,更多相關內(nèi)容需要的小伙伴可以參考下面文章內(nèi)容2022-06-06SpringBoot實現(xiàn)文件的上傳、下載和預覽功能
在Spring Boot項目中實現(xiàn)文件的上傳、下載和預覽功能,可以通過使用Spring MVC的MultipartFile接口來處理文件上傳,并使用HttpServletResponse或Resource來實現(xiàn)文件下載和預覽,下面是如何實現(xiàn)這些功能的完整示例,需要的朋友可以參考下2024-08-08Spring Boot接收單個String入?yún)⒌慕鉀Q方法
這篇文章主要給大家介紹了關于Spring Boot接收單個String入?yún)⒌慕鉀Q方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring boot具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-11-11spring啟動后保證創(chuàng)建的對象不被垃圾回收器回收
最近看到一個問題是,spring在啟動后如何保證創(chuàng)建的對象不被垃圾回收器回收?。所以本文結(jié)合jvm的垃圾回收機制和spring中的源代碼做出自己的一點猜測。有需要的朋友們可以參考借鑒。2016-09-09詳解Spring/Spring boot異步任務編程WebAsyncTask
這篇文章主要介紹了詳解Spring/Spring boot異步任務編程WebAsyncTask,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06