唯一可靠修复方式是全面使用sqlparameter参数化查询替代所有字符串拼接,严查executenonquery/executereader调用点,显式指定sqldbtype与长度,禁用动态表名拼接和存储过程内exec,连接字符串加charset=utf8防宽字节注入。

直接上 SqlParameter,别碰任何字符串拼接逻辑——这是唯一能落地、不改架构、且旧版 ASP.NET(.NET Framework 2.0–4.0)原生支持的修复方式。
查全所有 ExecuteNonQuery 和 ExecuteReader 调用点
漏洞不在“有没有参数化”,而在“有没有漏掉”。老项目里大量隐藏在后台导出页、统计报表、临时调试接口中的 SQL 拼接,往往被忽略。
- 搜索全部
.aspx.cs和.asmx文件,定位所有含ExecuteNonQuery、ExecuteReader、ExecuteScalar的代码块 - 特别注意
Request["xxx"]、Request.QueryString["xxx"]、Request.Form["xxx"]出现在 SQL 字符串里的位置——哪怕只出现一次,就是高危点 - 不要信任
Request["xxx"]:它会自动从 QueryString、Form、Cookies、ServerVariables 中依次查找,攻击面比你想象的宽得多
替换时必须显式指定 SqlDbType 和长度
用 AddWithValue 看似省事,但会触发隐式转换,导致索引失效、截断、甚至绕过类型校验。
- 字符串参数必须用
SqlDbType.NVarChar+ 显式长度,例如:new SqlParameter("@name", SqlDbType.NVarChar, txtName.Text.Length) { Value = txtName.Text } - 数字型参数(如
id=123)同样要走SqlParameter,不能只防字符串;否则id=1 OR 1=1仍可穿透 - 避免
string.Format()或"SELECT * FROM " + tableName:表名、列名、ORDER BY子句无法参数化,拼接即高危
存储过程里禁用 EXEC(@sql) 和动态 sp_executesql
把 SQL 下推到数据库不等于安全。很多老项目以为“用了存储过程就防注入”,结果在过程体内又拼接了用户输入。
- 检查所有存储过程中是否含
EXEC(@sql)、EXEC sp_executesql @sql、EXEC('SELECT ... ' + @param) - 若必须动态构造对象名(如分表查询),只能靠白名单校验,例如:
if (tableName != "Orders_2023" && tableName != "Orders_2024") throw new ArgumentException(); - 连接字符串务必加
Charset=utf8(SQL Server 不需要,但若连 MySQL 必须加),防止宽字节注入(如%df%27)绕过过滤
最常被忽略的是:参数化只保护值,不保护语法结构。表名拼接、ORDER BY @col、WHERE 1=1 AND @cond 这类写法,无论加多少 SqlParameter 都无效——它们根本不是参数能覆盖的范畴。











