DynamicParameters本身不引入SQL注入风险,前提是所有用户输入仅通过Add()传值、不拼接SQL字符串、不用于ORDER BY/表名等非参数化场景,且避免AddWithValue传恶意片段。

DynamicParameters 本身不会引入 SQL 注入风险——只要你不把它当字符串拼接工具用。
DynamicParameters 安全的前提是参数化路径完整
DynamicParameters 是 Dapper 提供的「可扩展参数容器」,它和匿名对象一样走的是 ADO.NET 的 Parameters.Add() 底层机制。只要满足以下全部条件,就和 new { } 一样安全:
- 所有用户输入都只通过
Add()方法注入,不参与 SQL 字符串拼接 -
Add()的第一个参数是纯字符串字面量(如"@Email"),不是拼出来的变量名 - 第二个参数(值)直接传入原始输入,不提前拼进 SQL 字符串里
- 没调用过
AddWithValue()并传入拼接后的 SQL 片段(比如AddWithValue("@sql", $"AND Name = '{input}'"))
常见错误现象:
- 报
InvalidOperationException: No value given for parameter '@xxx':说明 SQL 里写了@xxx,但漏了Add("xxx", ...) - 查询结果异常或静默失败:可能因类型推断错误(如把
Guid当string),但这不会导致注入 - 实际执行了恶意语句(如删表):基本能锁定为某处手动拼了 SQL 字符串,和
DynamicParameters无关
哪些操作会让 DynamicParameters 变危险
DynamicParameters 是中立容器,风险来自用法:
-
parameters.Add("@sql", $"ORDER BY {userInput}");→ 错!列名不能参数化,这里直接拼了 SQL 结构 -
sql += " AND Status = " + userInput;→ 错!哪怕只有一处字符串拼接,整条语句就退化为非参数化 -
parameters.AddWithValue("@name", $"'{unsafeName}'");→ 错!把带引号的字符串当值传,数据库会把它当字面量字符串查,但逻辑已错,且可能被绕过(如输入admin' OR '1'='1) - 把整个 WHERE 条件作为字符串传给一个参数,再在 SQL 里用
EXEC(@where)或类似动态执行 → 错!Dapper 不管你 SQL 里怎么 EXEC,它只保证参数值不被解析为代码
DynamicParameters 真正该用的场景
它不是为了“更灵活地拼 SQL”,而是补足匿名对象做不到的事:
- 需要输出参数:
parameters.Add("@Total", dbType: DbType.Int32, direction: ParameterDirection.Output) - 要传表值参数(
DataTable或自定义IDynamicParameter) - 参数名必须动态生成(如根据请求字段决定加
@CreatedAfter还是@UpdatedBefore) - 显式控制类型(如
DateTimeOffset在旧版 Npgsql 中易被误判,需指定dbType: DbType.DateTimeOffset)
这些操作本身不破坏参数化,前提是值仍走 Add(),不回流到 SQL 字符串里。
真正容易被忽略的点在于:ORDER BY、GROUP BY、表名、schema 名等语法结构,无论用 DynamicParameters 还是匿名对象,都根本无法参数化。它们必须靠白名单校验或枚举映射隔离,一旦放开自由输入,Dapper 完全无感,也不会报错,攻击就成功了。

















