首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

JDBC 防 SQL 注入實戰:Statement vs PreparedStatement 登錄驗證對比演示

     編輯:MySQL 綜合教學

JDBC 防 SQL 注入實戰:Statement vs PreparedStatement 登錄驗證對比演示

SQL 注入是 Web 安全頭號殺手。本文通過用戶登錄驗證案例,對比 Statement 拼接 SQL 導致注入漏洞、PreparedStatement 參數化查詢徹底防禦的完整過程,含代碼、測試數據、攻擊載荷構造與原理解析。

測試環境準備

CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(30),
    password VARCHAR(30)
);
INSERT INTO users VALUES (1, 'wonderq', 'root');
INSERT INTO users VALUES (2, 'chenxin', 'sweet');

漏洞版本:Statement 字符串拼接

public void loginVulnerable(String username, String password) {
    String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
    System.out.println("執行 SQL: " + sql);
    try (Connection con = ConnectionSource.getConnection();
         Statement stmt = con.createStatement();
         ResultSet rs = stmt.executeQuery(sql)) {
        if (rs.next()) System.out.println("登錄成功!");
        else System.out.println("登錄失敗!");
    } catch (SQLException e) { throw new RuntimeException(e); }
}

攻擊測試

正常登錄:`loginVulnerable("wonderq", "root")` → 成功。

注入攻擊:`loginVulnerable("chenxin", "a' OR 'b'='b")`

生成 SQL:

SELECT * FROM users WHERE username = 'chenxin' AND password = 'a' OR 'b'='b'

結果:`WHERE` 條件恆真 (`'b'='b'` 為 true),**繞過密碼驗證直接登錄成功**!

安全版本:PreparedStatement 參數化

public void loginSecure(String username, String password) {
    String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
    System.out.println("執行 SQL: " + sql);
    try (Connection con = ConnectionSource.getConnection();
         PreparedStatement ps = con.prepareStatement(sql)) {
        ps.setString(1, username); // 佔位符 1
        ps.setString(2, password); // 佔位符 2
        try (ResultSet rs = ps.executeQuery()) {
            if (rs.next()) System.out.println("登錄成功!");
            else System.out.println("登錄失敗!");
        }
    } catch (SQLException e) { throw new RuntimeException(e); }
}

攻擊測試 (同樣載荷)

`loginSecure("chenxin", "a' OR 'b'='b")`

結果:登錄失敗。

原理:PreparedStatement 預編譯階段已確定 SQL 邏輯結構 (`username = ? AND password = ?`),執行階段將用戶輸入 **作為字面量字符串** 綁定到參數,而非 SQL 片段。輸入 `"a' OR 'b'='b"` 被視為完整密碼字符串查找,數據庫中無此密碼,自然失敗。

核心差異總結

維度StatementPreparedStatement
SQL 構建運行時字符串拼接預編譯 + 參數綁定
邏輯結構可被用戶輸入篡改編譯期固定,不可變
注入風險極高無 (參數視為數據)
性能每次解析優化預編譯複用執行計劃
適用場景極簡腳本、DDL**所有業務 DML 查詢**

最佳實踐鐵律

  1. 全項目禁用 Statement 執行 DML (SELECT/INSERT/UPDATE/DELETE),強制使用 PreparedStatement。
  2. ORM 框架 (MyBatis/JPA) 內部已參數化,但警惕 `
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved