1. SQL 注入的成因与危害是什么,为什么参数化查询/预编译语句能从根上防御而字符串拼接不能?
SQL 注入产生的根本原因是什么,它会造成什么危害?为什么参数化查询或预编译语句能够从根上防御 SQL 注入,而字符串拼接方式则不能?
- SQL 注入的成因:用户输入被当作 SQL 命令的一部分拼接执行
- 参数化/预编译语句将数据与代码分离的原理
- 字符串拼接导致攻击者控制语法结构的本质
SQL 注入的成因是程序把外部输入直接拼接进 SQL 语句,使输入中的单引号、分号、注释符等被解释为 SQL 语法而非数据。攻击者构造 ' OR '1'='1 或 '; DROP TABLE users; -- 这类输入即可绕过鉴权、篡改数据、越权读取甚至执行系统命令。危害包括数据泄露、数据篡改、权限提升、拒绝服务乃至整库沦陷。参数化查询(Prepared Statement)先把 SQL 模板发给数据库完成解析与编译,之后再用占位符绑定参数值,此时数据库把参数严格当作字面量数据处理,不再参与语法解析,因此无法注入。字符串拼接方式则让用户输入在编译前就进入 SQL 文本,攻击者可改变语句结构,本质上是"数据与代码未分离"。
核心在于"编译时"与"运行时"的分离。预编译在参数进入前就固定了 SQL 结构,注入只能停留在数据层,构不成语法。这是结构性防御,而非对输入做黑名单过滤等"堵"式手段,所以能根除该漏洞。
# 不安全:字符串拼接
user = request.form['username']
sql = "SELECT * FROM users WHERE name = '" + user + "'"
cursor.execute(sql)
# 安全:参数化查询
sql = "SELECT * FROM users WHERE name = %s"
cursor.execute(sql, (user,))