SqlDataAdapter本身不防SQL注入,关键在于传入的SQL字符串是否参数化;必须将用户输入通过Parameters.Add()绑定为参数,禁用任何字符串拼接。

直接改 SqlDataAdapter 本身不能解决 SQL 注入——它只是数据填充工具,不负责构造 SQL。真正要动的是你传给它的 SELECT 语句字符串。老项目里常见写法是拼接 SQL 字符串再丢给 SqlDataAdapter,这正是漏洞根源。
为什么 SqlDataAdapter(string sql, conn) 会出问题
很多人误以为换用 SqlDataAdapter 就比手写 SqlCommand 安全,其实不然。只要初始化时传入的是拼接的字符串,比如:
string sql = $"SELECT * FROM Users WHERE Name = '{name}' AND Status = '{status}'";
SqlDataAdapter adapter = new SqlDataAdapter(sql, connection);
攻击者仍可输入 admin' OR '1'='1 让整句变成 WHERE Name = 'admin' OR '1'='1' AND Status = '...',条件恒真。
关键点:不是 SqlDataAdapter 不安全,而是你喂给它的 SQL 是“裸字符串”。
必须把拼接 SQL 改成参数化查询
改法核心只有一条:把所有用户可控的值,从字符串拼接中剥离,改用 @paramName 占位符 + Parameters.Add() 绑定。
- 原写法(危险):
new SqlDataAdapter("SELECT * FROM Orders WHERE CustomerId = " + id, conn) - 正确写法(安全):
new SqlDataAdapter("SELECT * FROM Orders WHERE CustomerId = @id", conn),然后手动给adapter.SelectCommand.Parameters.AddWithValue("@id", id)
注意:SqlDataAdapter 的 SelectCommand 是 SqlCommand 类型,你可以直接访问并设置参数:
SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Products WHERE Category = @cat", connection);
adapter.SelectCommand.Parameters.AddWithValue("@cat", Request.Form["category"]);
如果原来用了 UpdateCommand/DeleteCommand,它们也必须同样参数化——否则更新/删除操作照样可被注入。
老项目批量改造时最容易踩的坑
旧代码往往混用多种风格:有的地方用 string.Format,有的用 $"...",还有的在存储过程中又拼了一层。改的时候要盯住三处:
-
SqlDataAdapter初始化时传的 SQL 字符串(最常见漏点) -
adapter.SelectCommand.CommandText后续是否又被重新赋值为拼接字符串(动态重设很隐蔽) - 是否误用
AddWithValue导致类型推断错误(比如把数字当字符串传,引发隐式转换性能问题;虽不导致注入,但可能拖慢查询)
特别提醒:不要试图在 SQL 字符串里“替换单引号”或“过滤 or、union”来“修复”拼接逻辑——这类黑名单过滤既不可靠(绕过方式太多),又破坏业务字段内容(比如真实用户名含 or 就被拦了)。
参数化是唯一可靠路径。哪怕只改一个接口,也要确保从请求入口到 SqlDataAdapter 这条链上,没有一次字符串拼接触碰用户输入。

















