温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

动态SQL如何防止注入

发布时间:2026-09-08 22:50:12 来源:亿速云 阅读:90 作者:小樊 栏目:数据库

动态 SQL(Dynamic SQL) injection 是一个常见且高风险的安全问题。下面从原理 → 防护手段 → 不同场景示例系统说明如何防止注入。


一、SQL 注入的根本原因

动态 SQL 通常是把用户输入拼接到 SQL 字符串中

"SELECT * FROM user WHERE name = '" + name + "'"

如果 name = "admin' --"
最终 SQL 变成:

SELECT * FROM user WHERE name = 'admin' --'

攻击者可以操控 SQL 逻辑。

核心原则:永远不要直接拼接用户输入到 SQL 中


二、防止 SQL 注入的主要手段(按优先级)

✅ 1. 使用「参数化查询 / 预编译语句」(最重要)

这是最有效、最推荐的方式。

Java(JDBC)

String sql = "SELECT * FROM user WHERE name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);

MyBatis

<select id="getUser">
  SELECT * FROM user WHERE name = #{name}
</select>

#{} 是参数化
${} 是直接拼接(易注入)

Python

cursor.execute(
  "SELECT * FROM user WHERE name = %s",
  (name,)
)

✅ 2. 避免在动态 SQL 中使用 ${}

在 MyBatis、XML、模板 SQL 中:

写法 是否安全
#{} ✅ 安全
${} ❌ 不安全(除非极特殊场景)

❌ 错误示例:

ORDER BY ${column}

✅ 安全替代:

<choose>
  <when test="sort == 'name'">ORDER BY name</when>
  <when test="sort == 'age'">ORDER BY age</when>
</choose>

✅ 3. 白名单校验(用于表名 / 字段名 / 排序)

表名、字段名不能参数化,必须用白名单:

Set<String> allowed = Set.of("name", "age", "email");
if (!allowed.contains(column)) {
    throw new IllegalArgumentException("非法字段");
}

✅ 4. 输入校验与类型约束

  • 数字 → 强制 Integer / Long
  • 邮箱 → 正则
  • 枚举 → 只允许固定值
  • 长度限制

✅ 5. 最小权限原则

数据库账号:

  • 不允许 DROP
  • 不允许 FILE
  • 只给业务所需权限

✅ 6. 使用 ORM(更安全)

  • MyBatis(配合 #{}
  • Hibernate / JPA
  • SQLAlchemy

ORM 默认使用参数化查询。


三、动态 SQL 安全示例(MyBatis)

❌ 危险

SELECT * FROM user
WHERE name = '${name}'

✅ 安全

SELECT * FROM user
WHERE name = #{name}

✅ 动态条件(安全)

<where>
  <if test="name != null">
    AND name = #{name}
  </if>
  <if test="age != null">
    AND age = #{age}
  </if>
</where>

四、常见误区

❌ “转义引号就够了”
❌ “前端校验能防注入”
❌ “内部系统不用防”

这些都不安全。


五、总结一句话

动态 SQL 防注入 = 参数化查询 + 白名单 + 输入校验 + 最小权限

如果你用的是 MyBatis / JPA / JDBC / Python / Node,我可以给你针对具体代码的防注入写法。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI