文章总结: 本文探讨预编译(参数化查询)对SQL注入的防御效果,指出预编译虽能有效防止值参数位置的注入,但无法用于SQL标识符(如排序方式、表名等)。文章通过代码示例展示安全与不安全场景,强调在不可参数化位置需结合白名单机制才能完美防御注入漏洞。 综合评分: 85 文章分类: WEB安全,安全开发,漏洞分析,应用安全,技术标准
预编译真的能完美防御sql注入吗?
原创
Relish_Chen Relish_Chen
RelishSec
2026年4月17日 14:38 福建
在小说阅读器读本章
去阅读
前言
作为网安人,对开发的了解不像开发者那样深入,所以在我的认知中,要防御sql注入漏洞的最好方式是采用预编译(参数化查询),也就是只要采用预编译了,此处就不会有sql注入漏洞,但是在近期的学习中发现在某些时候,预编译却无法防御sql注入漏洞
安全的场景
如果我们要实现输入用户名,根据用户名在数据库中查询对应的信息,那么在开发眼中,使用预编译就能很好的防御sql注入漏洞
username = input("请输入用户名: ")sql = f"SELECT * FROM student WHERE name = %s;"cursor.execute(sql, (username,))results = cursor.fetchall()for row in results: print(row)
在这个代码中,我们不管传入什么,都会被当作一个字符串,pymysql会自动处理我们传入的内容,如果传入zs’or’1那么执行的sql语句会是:
SELECT * FROM student WHERE name = 'zs\'or\'1';
他会把我们传入的zs’or’1当作是一个字符串来处理,这样就能防止sql注入
不安全的场景
username = input("请输入用户名: ")sql = f"SELECT * FROM student WHERE name = '{username}'"cursor.execute(sql)results = cursor.fetchall()for row in results: print(row)
这个时候他将我们传入的username直接拼接在sql语句中,如果我们传入1’or’1就会把所有数据查询出来,造成了sql注入
预编译限制
在安全的场景下,我们写了一个%s占位符,%s表示字符串,不管我们传入什么都当作是一个字符串,但如果业务需要查询的数据需要我们传入的不是字符串呢?比如在排序中,我们可以传入asc和desc,那么我们不能这样写代码,否则会报错
order_by = input("请输入排序方式: ")sql = "SELECT * FROM student ORDER BY id %s"cursor.execute(sql, (order_by,))results = cursor.fetchall()for row in results: print(row)
这是因为预编译不能参数化排序方式,为什么呢?因为排序方式不能是字符串,你想想,你写sql语句会这样写吗?
SELECT * FROM student ORDER BY id 'desc';
所以,预编译只能防御住可参数化位置的sql注入
不可参数化的位置还有tables、columns、order by、group by、limit等
预编译能防止sql注入吗
因此,如果业务要实现用户传入类似排序方式时,不可可以采用预编译,那么,如果业务要实现该功能,可能会这样写
order_by = input("请输入排序方式: ")sql = f"SELECT * FROM student ORDER BY id {order_by}"cursor.execute(sql)results = cursor.fetchall()for row in results: print(row)
那么这样子写就引发sql注入了,比如我传入desc,0和desc,1就能发现存在sql注入了
那么,如何防御?只需要加上白名单
order_by = input("请输入排序方式: ").lower()if order_by not in ['asc','desc']: passelse: sql = f"SELECT * FROM student ORDER BY id {order_by};" cursor.execute(sql) results = cursor.fetchall() for row in results: print(row)
这样就能完美防御sql注入了
总结
预编译的占位符只能用于值参数,不能用于SQL标识符,否则会被当成字符串常量,导致排序/动态查询功能失效。开发为了实现业务功能只能拼接字符串,如果没有设置白名单,攻击者就能直接突破预编译的防护
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:RelishSec RelishChen RelishChen《预编译真的能完美防御sql注入吗?》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论