真正有效的sql注入防护必须在数据库访问层实现参数化查询,全局过滤仅是易误杀漏过的临时补丁;应禁用fromsqlinterpolated,严格使用fromsqlraw与sqlparameter[],动态标识符须白名单校验,全局检测仅作日志告警。

不能在全局层“拦截并过滤”SQL注入请求——真正有效的防护必须发生在数据库访问层,全局过滤只是临时补丁,且极易误杀或漏过。
为什么全局过滤不是正解
SQL注入的恶意载荷(如 '--、%27OR%201%3D1、/*)可能藏在任意位置:Query String、Form Data、JSON Body、Header 甚至 Cookie。但关键点在于:这些字符串本身不危险,危险的是它们被拼进 SQL 语句时未加参数化处理。
- 你在
OnActionExecuting里删掉所有select字样?那用户搜“select * from products”就 403 - 你对
HttpContext.Request.Body做全文扫描?会消耗流,导致后续控制器收不到 JSON 数据(静默失败) - 你用正则匹配
union?字段名叫union_id或昵称含SELECTOR就被干掉
必须在数据库访问层做参数化,别绕开
EF Core 或 ADO.NET 的执行路径,才是唯一能决定 SQL 是否安全的环节。任何试图在它之前“拦住攻击”的做法,都是削足适履。
- 禁用
FromSqlInterpolated:它看起来像参数化,实则底层仍做字符串插值,$"SELECT * FROM {table}"一样危险 - 只用
FromSqlRaw(sql, parameters),且parameters必须是SqlParameter[]或命名对象,不能是裸字符串数组 - ADO.NET 中,
SqlCommand.Parameters.Add()是硬性要求;严禁用AddWithValue,null 值可能触发类型推断错误,某些驱动退化为字符串拼接 - 动态表名/列名(如排序字段
ORDER BY @sortField)无法参数化,必须走白名单:new[] { "name", "email", "created_at" }.Contains(input)
如果真要加一层全局检测,只做三件事
这不是防线,是日志+告警+兜底。它不阻止请求,只标记可疑行为供人工复核。
- 在
OnActionExecuting中,只检查context.ActionArguments(模型绑定后干净数据),不碰原始 Body/Query —— 避免流耗尽 - 若必须查原始 Query,先调
context.HttpContext.Request.QueryString.Value;查 Body 前,必须先EnableBuffering()并重置Position = 0 - 关键词检测前,必须先
WebUtility.UrlDecode()和WebUtility.HtmlDecode();正则加\b词边界;覆盖注释符:--、/*、#;跳过 ASP.NET 内置字段(__RequestVerificationToken、__viewstate,大小写不敏感) - 匹配成功后,不返回错误,只记录完整上下文:
IP、Path、原始参数值、时间戳,并触发告警
最容易被忽略的细节
开发者常以为“加了关键词过滤就安全了”,却没注意:URL 编码过的 %27 不解码就匹配不到;ORDER BY name ASC 里的 ASC 被当成关键词误杀;AddWithValue 在 SQL Server 2019+ 上对 null 推断为 nvarchar(1),导致后续 LIKE 查询截断——这些都不是攻击,却是真实发生的故障。











