导出Excel功能中直接拼接用户输入的WHERE条件、ORDER BY字段、LIMIT参数等均属SQL注入高发场景,必须采用参数化查询、白名单校验、整型强转及错误脱敏等综合防护措施。

导出Excel功能里直接拼接用户输入的查询条件,是SQL注入高发场景——只要用了 f"WHERE ... {user_input}" 或 str.format() 这类方式,基本等于给攻击者开了后门。
导出接口里 WHERE 条件拼接必须改参数化
导出功能常因“灵活筛选”而动态构造 WHERE 子句,比如按时间范围、状态、关键词搜索后导出。开发者容易图省事用字符串拼接,但这是最危险的做法。
- ❌ 错误写法:
"SELECT * FROM orders WHERE status = '" + request.args.get("status") + "'" - ✅ 正确做法:所有可变条件都走参数占位符,哪怕有多个或嵌套逻辑
- 注意
IN语句不能直接参数化单个占位符对应多个值,需动态生成等量占位符(如WHERE id IN (?, ?, ?)),再绑定列表 - 如果用 ORM(如 Django ORM、SQLAlchemy),优先走
.filter()链式调用,它底层自动参数化;避免混用 raw SQL + 字符串拼接
ORDER BY 和列名不能参数化,必须白名单校验
导出时用户常要求“按某列排序”,但 ORDER BY 后的内容无法用参数化处理——数据库不支持对排序字段做参数绑定。
- ❌ 危险写法:
"ORDER BY " + request.args.get("sort_field") - ✅ 安全做法:预定义合法字段映射表,例如
{"created_at": "created_at", "amount": "amount", "status": "status"},只允许从中取值 - 同理,导出时若支持“选列”,表头字段名也必须来自白名单,禁止透传用户输入的任意字符串作为列名或别名
- 特别注意别名中带空格或特殊符号(如
user_name AS `Full Name`)时,需额外验证格式,避免反引号逃逸
导出数据量大时,LIMIT/OFFSET 仍要防注入
有些导出接口为防超载会加 LIMIT 控制返回条数,但数字型参数若没强制转整型,仍可能被绕过。
- ❌ 危险写法:
"LIMIT " + request.args.get("limit")—— 攻击者可传10; DROP TABLE users; - ✅ 安全做法:对
limit、offset等数字参数,先int()强转,再设硬上限(如最大 10000),超出则报错或截断 - 若业务真需要导出百万级数据,应改用分页导出+后台任务,而非单次大查询
- 注意 PostgreSQL 的
LIMIT ALL可能被利用,显式禁止该字符串出现在参数值中
错误信息必须脱敏,否则暴露表结构
导出失败时,如果把原始数据库错误(比如 Unknown column 'xxx' in 'where clause')直接返回给前端,等于帮攻击者测绘数据库结构。
- ❌ 危险行为:未捕获异常,或
except Exception as e: return str(e) - ✅ 必须做:在导出逻辑外层统一
try/except,捕获 DBAPIError 等具体异常,只返回通用提示如"导出失败,请稍后重试" - 同时记录完整错误日志(含原始 SQL、参数、堆栈),供内部排查,但绝不透出到响应体
- 尤其注意 MySQL 的
Error 1064、PostgreSQL 的ERROR: syntax error这类提示,都是典型注入探针反馈
真正麻烦的不是写几行参数化代码,而是导出功能往往跨多层模块——前端传参、中间服务组装条件、DAO 层执行——只要其中一环松动,整条链就失效。最容易被忽略的是排序字段和分页参数,它们不像 WHERE 条件那样显眼,却一样致命。


















