sql注入防护靠参数化查询,如preparedstatement、psycopg2占位符、pg库$1绑定;并发限流需在入口层实现,如resilience4j、nginx limit_req或redis滑动窗口,而非sql层。

SQL注入防护和并发限流是两件不同的事
很多人把防 SQL 注入和限制 SQL 执行频率混为一谈,其实它们解决的是完全不同的问题:SQL 注入 是输入校验与执行安全问题,靠参数化查询或 ORM 防御;而并发频率限制 是服务稳定性问题,防止恶意刷接口或突发流量压垮数据库。强行用“数据流控”去堵 SQL 注入,既无效,又容易误伤正常请求。
真正防 SQL 注入,只靠 PreparedStatement 或等价机制
无论后端用 Java、Python 还是 Node.js,只要拼接 SQL 字符串,就存在风险。唯一可靠的方式是交由数据库驱动做参数绑定:
- Java 用
PreparedStatement,所有用户输入必须走setString()、setLong()等方法,绝不能用String.format()或+拼接 - Python 的
psycopg2要用%s占位符(不是.format()),sqlite3用?,且参数必须是 tuple 或 dict,不能是 f-string - Node.js 的
pg库必须用client.query('SELECT * FROM users WHERE id = $1', [id]),禁止`SELECT * FROM users WHERE id = ${id}` - ORM 如 Django ORM、SQLAlchemy、MyBatis-Plus 默认启用参数化,但一旦用了
raw()、text()、@Select("...${xxx}...")就立刻退化回高危模式
要限流,得在请求入口层做,不是在 SQL 层
数据库本身不提供“每秒最多执行 N 条 SELECT”的策略。想控制 SQL 并发量,必须前置到应用或网关层:
- Web 框架层(如 Spring Boot)可用
Resilience4j的RateLimiter,按用户 ID 或 IP 统计接口调用频次,超限直接返回429 Too Many Requests - 反向代理层(如 Nginx)配
limit_req,例如limit_req zone=api burst=10 nodelay,适合粗粒度防护 - Redis + Lua 做分布式滑动窗口限流:每次请求先
INCRkey,再EXPIRE,并用eval保证原子性;key 可设计为rate:uid:{user_id}:20240520 - 切忌在 DAO 层对
executeQuery()做 synchronized 或计数器——这会阻塞线程池,反而放大雪崩风险
误用“SQL 流控”可能掩盖更严重的问题
如果发现某条 SQL 需要被频繁限流,大概率说明它本身就有缺陷:
- 没加索引导致慢查,被反复重试 → 应该看
EXPLAIN和慢日志,而不是限流 - 前端轮询未退避,每秒发 20 次相同请求 → 应该改前端逻辑或加服务端缓存(如
Cache-Control或 Redis) - 一个用户触发大量关联查询 → 需拆分接口、引入分页或异步化,而非用限流硬扛
- 把限流阈值设得过高(比如每秒 1000 次),等于没设;设得太低(比如每秒 1 次),又会让合法批量操作失败
真正的瓶颈往往不在 SQL 执行次数,而在连接数、锁等待、磁盘 I/O 或网络往返。盯着“SQL 并发数”调参,容易忽略这些底层信号。










