防范动态 SQL 注入的核心原则是:永远不要相信用户输入,永远不要把用户输入直接拼进 SQL。下面从原理、常见场景和防护措施三个层面系统说明。
动态 SQL 指的是在代码中拼接字符串生成 SQL 语句,例如:
"SELECT * FROM user WHERE name = '" + userName + "'"
如果 userName 来自用户输入,攻击者可以输入:
' OR '1'='1
最终 SQL 变成:
SELECT * FROM user WHERE name = '' OR '1'='1'
导致绕过认证、越权查询、数据泄露甚至删库。
String sql = "SELECT * FROM user WHERE id = " + id;
$sql = "SELECT * FROM user WHERE name = '$name'";
sql = f"SELECT * FROM user WHERE id = {uid}"
这是最有效、最通用的防护手段。
PreparedStatement ps =
conn.prepareStatement("SELECT * FROM user WHERE id = ?");
ps.setInt(1, id);
<select id="getUser">
SELECT * FROM user WHERE id = #{id}
</select>
✅
#{}是参数化
❌${}是字符串替换(容易注入)
$stmt = $pdo->prepare("SELECT * FROM user WHERE id = ?");
$stmt->execute([$id]);
cursor.execute("SELECT * FROM user WHERE id = %s", (user_id,))
ORM 会自动参数化 SQL:
User.objects.get(id=user_id)
✅ 只要不手写 SQL,基本安全
适用于:
Set<String> allowSort = Set.of("id", "create_time");
if (!allowSort.contains(sortField)) {
throw new IllegalArgumentException();
}
✅ 只允许“确定安全的值”
数据库账号权限最小化:
DROP TABLE
xp_cmdshell
<if test="name != null">
AND name = '${name}'
</if>
<if test="name != null">
AND name = #{name}
</if>
| 误区 | 说明 |
|---|---|
| 用正则过滤单引号 | ❌ 可被绕过 |
| 前端校验 | ❌ 不可信 |
| 转义字符 | ❌ 不可靠 |
| 参数化 + 拼接 | ❌ 仍可能注入 |
防动态 SQL 注入 = 参数化查询 + 不拼接 SQL + 白名单校验 + 最小权限
如果你愿意,我可以:
只要把场景发我即可。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。