sql注入漏洞源于字符串拼接传参,参数化查询必须严格匹配驱动语法,orm的extra()/raw()/动态字段名及sqlalchemy的text()均非绝对安全,exec/eval更属高危,唯一可靠方案是全程参数化+白名单校验。

cursor.execute 传参错用字符串拼接,就是 SQL 注入的直接入口。只要用户输入进了 f"SELECT * FROM user WHERE id = {user_id}" 或 "%s" % name 这类表达式,漏洞就已经存在,没有“轻微”或“可控”一说。
psycopg2 / pymysql / sqlite3 的占位符不能混用
不同驱动对参数化语法的支持差异极大,硬套一种写法在换库时必然失效甚至静默出错:• sqlite3 只认 ?(位置)或 :name(命名),传 %s 会被当字面量处理,不报错但查不到数据
• psycopg2 只认 %s,且第二参数必须是 tuple 或 dict;传 [user_id] 会抛 TypeError: not all arguments converted
• pymysql 默认支持 %s,但不支持 %()s 命名格式;若要用命名参数,得显式开启 named=True
正确示例(psycopg2):cursor.execute("SELECT * FROM user WHERE id = %s AND status = %s", (user_id, "active"))
错误示例:cursor.execute("SELECT * FROM user WHERE id = %s", [user_id]) —— 列表不被接受
更危险的写法:cursor.execute(f"SELECT * FROM user WHERE name = '{name}'") —— 字符串拼接,高危
Django ORM 的 extra()、raw() 和动态字段名不是安全区
ORM 查询集本身安全,但以下三处常被误认为“用了 ORM 就万事大吉”:• extra() 和 raw() 绕过 ORM 层,直接执行 SQL;参数必须走 params= 关键字传入,不能拼进字符串里
• filter(**{field_name: value}):若 field_name 来自用户请求(如搜索字段),攻击者可传 __dict__ 或 is_staff 等字段名,触发非预期查询
• Q 对象构造时用了 eval() 或 format(),比如 Q(eval(request.GET.get("q_expr"))),等于把控制权交给了攻击者
安全做法是白名单校验:allowed_fields = {"id","name","email","created_at"},再做 if field not in allowed_fields: field = "id"
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
SQLAlchemy 的 text() 不是免检通行证
text() 常被当作“ORM 里写原生 SQL 的安全出口”,但它只在满足两个条件时才真正防注入:
• text() 内部 SQL 必须是纯静态字符串,不含任何用户输入
• 所有动态值必须通过第二参数(dict 或 tuple)传入,且占位符只能是 :name(命名)或 ?(位置)
危险写法:db.session.execute(text(f"SELECT * FROM user WHERE name = '{name}'"))
或 db.session.execute(text("SELECT * FROM user WHERE " + condition))
这两者中,变量已提前插进 SQL 字符串,text() 完全失效
exec() 和 eval() 在数据库上下文中极度危险
如果代码里出现exec() 或 eval(),且内容含 "SELECT"、"INSERT"、.execute( 等关键词,基本可以判定为高危漏洞:
• 没有安全的字符串拼接 SQL 方案,正则预过滤只是拖延时间,无法覆盖所有绕过手法
• 即使做了 int() 转换,也不能防注入:id = ${parseInt(req.query.id)} 中,"1 OR 1=1" 仍会被转成 1,后续若又拼回 SQL 就崩了
• 自写 escape_sql() 几乎必然漏场景(如 MySQL 宽字节、反斜杠转义绕过),且无法适配多数据库方言
最稳妥的做法:删掉 exec,改用参数化查询接口;若真需动态 SQL,必须严格拆解为结构化操作(如白名单表名 + 白名单字段 + 参数化值),而不是拼字符串
真正难的不是写对一行 cursor.execute,而是守住所有可能把用户输入塞进 SQL 字符串的地方——包括模板、日志、调试语句、第三方库的 raw 接口,以及那些写着“临时用一下”的 exec 表达式。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










