f-string拼接SQL必然导致SQL注入,因字符串在Python层已拼合完成,数据库驱动无法介入参数化处理。

f-string拼接SQL语句极度危险,因为数据库驱动完全不介入字符串生成过程,用户输入直接成为可执行SQL语法的一部分——这不是“可能被注入”,而是“必然可注入”,只要输入含单引号、分号或注释符,就能绕过任何前端校验。
为什么f-string拼接SQL会触发SQL注入
DB-API驱动(如sqlite3、psycopg)只识别execute()第二个参数中的占位符(如?或%s),而f-string在Python层就完成了全部字符串替换,传给驱动的已是恶意拼好的语句。比如:
user_input = "admin' --"
query = f"SELECT * FROM users WHERE username = '{user_input}'"
# 实际执行的是:SELECT * FROM users WHERE username = 'admin' --'此时--后的内容被注释,WHERE条件失效,结果等价于全表扫描。
- 即使
user_input是数字类型,也挡不住构造为1 OR 1=1; DROP TABLE users; -
str.format()和%格式化同理危险,它们只是换种写法,不改变“字符串提前拼合”的本质 - 数据库权限若足够高,
;可分隔多条语句,造成删库、写文件等更严重后果
动态字段名/表名必须走白名单校验
参数化查询只支持值(value)占位,不支持标识符(identifier)占位。所以read_sql_query("SELECT * FROM ?", con, params=["users"])会报错——?只能代入WHERE后的值,不能代入FROM后的表名。
- 正确做法:用
in硬校验+字面量拼接,例如if table_name in ["users", "orders"]:再用f-string拼f"SELECT * FROM {table_name}" - 字段排序等动态部分同样处理:
if sort_col in ["created_at", "score"]:才拼f"ORDER BY {sort_col} DESC" - 绝对禁止对用户输入做
strip()、replace(";", "")等“简单过滤”——绕过手法太多,如score/**/ASC或宽字节编码
Django QuerySet中f-string的隐蔽陷阱
Django的双下划线查询(如__icontains)本身是参数化的,但一旦用f-string包裹,就提前破坏了这一机制:
# ❌ 危险:f-string在Python层拼出'%<user_input>%',再传给QuerySet
Person.objects.filter(name__icontains=f'%{user_input}%')
<h1>✅ 安全:让QuerySet自己处理参数绑定</h1><p>Person.objects.filter(name__icontains=user_input)- 前者等价于把恶意字符串
%admin' OR '1'='1%直接塞进SQL的LIKE子句 - 后者由Django ORM自动生成带
%s占位符的预编译语句,输入作为纯数据绑定 - 所有
filter()、exclude()、annotate()调用都应保持参数裸传,不经过任何字符串插值
安全拼接SQL的最小可行方案
没有“又方便又安全”的万能方案,只有明确分工:结构部分靠白名单+字面量,数据部分靠参数绑定。复杂查询建议拆成两步:
- 先定义允许的结构选项:
ALLOWED_TABLES = {"log": "app_logs", "event": "user_events"} - 校验并拼结构:
table = ALLOWED_TABLES.get(user_table_key, "app_logs")→f"SELECT * FROM {table}" - 拼好结构后,再用
execute(query, (val1, val2))传参,确保所有WHERE、VALUES等位置全是占位符 - 多行SQL优先用三重引号+括号隐式连接,避免f-string混入任何用户变量:
query = ("""SELECT u.name, o.total """ "FROM users u JOIN orders o ON u.id = o.user_id " "WHERE u.status = ?")
最容易被忽略的一点:日志里打印SQL时,如果直接logger.info(f"Executed: {query} with {params}"),虽然不执行,但依然可能泄露敏感参数——应统一用logging.debug("Executed: %s", query)并禁用生产环境DEBUG日志。

















