API网关必须在最前端拦截SQL注入,因其是所有HTTP请求的必经入口,可统一校验URL、查询参数、表单、JSON、路径变量及Header/Cookie中的恶意载荷,而业务层防护对绕过App的直接调用完全失效。

API网关不是“能防SQL注入”,而是“必须拦在最前面”——因为所有请求必经它转发,而业务服务层的 PreparedStatement 或 ORM 校验,对绕过 App 直接调用接口的攻击者完全无效。
为什么网关层拦截不可替代
客户端发的每个 HTTP 请求,无论来自 App、Postman 还是 curl,都得先过网关。这意味着:
- 攻击者根本不需要破解 App,只要抓包改个
id=1%20OR%201%3D1就能试探后端是否拼 SQL - 后端即使用了
MyBatis的#{},也挡不住动态 SQL 场景(比如${sortField})或遗留报表模块硬拼字符串 - 网关可统一管控所有微服务,避免某个服务漏配校验导致整条链路失守
- 对
GET /search?q=admin'这类明文参数,网关能在毫秒级拒绝,不消耗业务服务 CPU 和数据库连接
哪些参数位置必须校验
网关默认只看 URL 路径和查询参数(request.getQueryParams()),但真实攻击常藏在别处:
-
application/x-www-form-urlencoded请求体:需显式调用ServerWebExchange.getFormData()解析,否则id=1'--会被直接透传 -
application/json请求体:必须用Flux<databuffer></databuffer>异步读取并解析为JsonNode,再递归遍历所有字符串字段;否则{"filter": "name = 'admin' OR 1=1"}完全看不见 - 路径参数(如
/user/{id}):需从ServerWebExchange.getAttribute("org.springframework.cloud.gateway.support.ServerWebExchangeUtils.uriTemplateVariables")提取,不能只扫 query - Header 和 Cookie:虽然少见,但
Cookie: session=' OR 1=1--也是有效攻击面,需按需开启扫描
校验规则怎么写才不误杀也不漏杀
关键词黑名单(如匹配 UNION SELECT)极易被大小写、空格、注释绕过,实际应组合三层判断:
- 基础特征:用
(?i)\b(SELECT|UNION|INSERT|UPDATE|DELETE|DROP|EXEC)\b,\b防止匹配到SELECTED,(?i)忽略大小写 - 可疑结构:匹配
;\s*--、'\s*OR\s*'1'\s*=\s*'1'、sleep\(\d+\),注意正则中括号要转义 - 上下文过滤:排除白名单字段名,如参数名为
sql_type且值为"count"或"detail",不应触发拦截 - 编码兼容:必须先做一次 URL 解码(
%27 → '),否则%27OR%201%3D1直接放行;Unicode 编码(%u0027)属于高阶需求,需额外加解码逻辑
严格模式下如何配置未知参数处理
启用「拒绝未知参数」策略(strict mode)是性价比最高的第一道过滤,但必须明确边界:
- 全局开关不推荐:用路由粒度控制,比如
/api/**启用,/admin/**关闭(后台 SQL 调试接口天然需要传原始 SQL) - 参数名校验要区分大小写:配置
userId就不该放过userid或USERID,否则可能绕过白名单 - JSON Body 的字段名校验需配合 Schema:仅靠 key 名匹配不够,要解析 JSON 后检查
filter字段值是否为字符串类型,避免把{"filter": {"type": "like"}}误判为 SQL 片段 - 禁用
Content-Type: text/plain或application/octet-stream的自动透传,这类请求体若含恶意 payload,网关默认不解析也不校验
真正容易被忽略的是:网关规则生效的前提是「它确实看到了数据」——如果没开请求体解析、没配 JSON 解码器、没处理 URL 编码,那再强的正则也等于没写。

















