topone233

导航

JavaWeb的SQL注入防护

操作符必须“枚举 + 映射”

public enum OpEnum {
    EQ("="),
    GT(">"),
    LT("<"),
    GE(">="),
    LE("<="),
    LIKE("LIKE"),
    IN("IN"),
    BETWEEN("BETWEEN");

    private final String sql;

    OpEnum(String sql) {
        this.sql = sql;
    }

    public String getSql() {
        return sql;
    }
}

value 永远不参与 SQL 拼接,只参与“参数绑定”

MyBatis 在运行时做的事情是:

找到 #{params.name}
↓
从参数 Map 里取 params.name
↓
绑定到 PreparedStatement

一、你写下 #{params.xxx} 之后,发生了 5 件事

我们用这个 SQL 举例:

and user_name LIKE #{params.name}

第 1 步:MyBatis 看见 #{}

MyBatis 解析 SQL 时,发现这是一个 参数占位符。

👉 它不会把值直接塞进 SQL 字符串。

第 2 步:SQL 被改写成「?」

真正发给数据库之前,SQL 长这样:

and user_name LIKE ?

⚠️ 这里非常关键:

SQL 结构已经固定

后面再也不能改结构了

第 3 步:MyBatis 调用 JDBC PreparedStatement

底层代码等价于:

PreparedStatement ps =
conn.prepareStatement(
"and user_name LIKE ?"
);

SQL 在这里已经“编译完”了。

第 4 步:value 作为“纯数据”被绑定

ps.setString(1, "%' or 1=1 --%");

注意这里:

没有拼接

没有解析

数据库 不知道你传的是什么语义

第 5 步:数据库执行

数据库看到的是:

SQL 结构:user_name LIKE ?
参数值:%' or 1=1 --%

数据库只会做一件事:

拿字符串,去匹配字段

不会:

重新 parse SQL

把参数当成 SQL 执行

执行 or 1=1

posted on 2026-02-10 00:03  你们真的很严格啊  阅读(10)  评论(0)    收藏  举报