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
浙公网安备 33010602011771号