.NET 6 中 EF Core 默认防 SQL 注入,安全点在 LINQ 方法(Where、Find 等)天然参数化;高危点是 FromSqlRaw/ExecuteSqlRaw 拼接用户输入,表名列名等结构需白名单校验。

只要不用 FromSqlRaw 或 ExecuteSqlRaw 拼接用户输入,.NET 6 中的 EF Core 默认就是防 SQL 注入的;真正出问题的地方,几乎都集中在手写原生 SQL 的环节。
Where、Find、First 等 LINQ 方法天然安全
这些方法底层走的是参数化执行,SQL 模板和变量值完全分离。即使传入 "admin' OR '1'='1" 这样的字符串,EF Core 也会把它当纯文本绑定为参数,不会解析成 SQL 逻辑。
-
context.Users.Where(u => u.Email == userInput)—— 安全,无需额外处理 -
context.Orders.Find(orderId)—— 安全,orderId是强类型 int 或 guid,根本没法注入 - 所有带 lambda 表达式的查询(
Single、Any、Count)都自动参数化
FromSqlRaw 和 ExecuteSqlRaw 是高危区
这两个方法明确要求你写原生 SQL,一旦用字符串插值或 string.Format 塞入用户输入,就等于把门打开让攻击者进来。
- ❌ 危险:
context.Users.FromSqlRaw($"SELECT * FROM Users WHERE Name = '{name}'") - ✅ 正确(位置参数):
context.Users.FromSqlRaw("SELECT * FROM Users WHERE Name = {0}", name) - ✅ 更推荐(命名参数):
context.Users.FromSqlRaw("SELECT * FROM Users WHERE Name = @name", new SqlParameter("@name", name)) - ⚠️ 注意:
FromSqlInterpolated看似用 $,但它会自动参数化变量,仅限直接插变量,不能插$"{name + "%"}"这类表达式
动态查询别拼 SQL 字符串
比如“按多个字段模糊搜索”,常见错误是用 StringBuilder 拼 WHERE 条件,再喂给 FromSqlRaw —— 这彻底绕过了 EF 的参数化机制。
- ❌ 错误:
sql.Append($"AND Name LIKE '%{keyword}%'")→ 最终喂给FromSqlRaw - ✅ 推荐:用
Expression构建动态条件,保持整个链路在 LINQ 体系内,例如用Linq.Dynamic.Core的Where("Name.Contains(@0)", keyword) - ⚠️ 如果真要用原生 SQL,表名、列名、
ORDER BY字段必须走白名单校验,参数化只防得住值,防不住结构
连接字符串和上下文配置也得盯紧
没人想到这里也能被注入,但现实中真有案例:连接字符串从配置中心读取,而攻击者通过篡改环境变量污染了 Application Name 或 Connect Timeout,间接影响连接行为或日志输出。
- 检查
ConnectionString来源是否可信,避免直接拼接用户可控字段 -
DbContext初始化时,不要把用户输入塞进optionsBuilder.UseSqlServer(...)的参数里 - 启用 EF Core 的敏感数据日志(
EnableSensitiveDataLogging)仅用于调试,上线必须关掉,防止参数值泄露
最常被忽略的一点:参数化能防住值,但防不住 SQL 结构本身 —— 列名、表名、排序方向、分页偏移量这些,必须靠白名单或枚举约束,不能只依赖参数占位符。

















