EF Core 不自动防SQL注入,FromSqlRaw和ExecuteSqlRaw必须手动参数化;FromSqlInterpolated仅安全处理纯变量插值,表名列名等结构部分须用白名单校验。
EF Core 本身不自动防注入,安全完全取决于你用哪条 API、怎么传参——FromSqlRaw 和 ExecuteSqlRaw 默认就是裸奔状态,不手动参数化等于把数据库钥匙直接交给用户。
FromSqlRaw 和 ExecuteSqlRaw 的坑这两个方法不做任何字符串解析或转义,只负责把传进去的字符串原样发给数据库驱动。哪怕只拼一个字段值,只要用了 + 或 $"" 插入用户输入,就立刻破防。
FromSqlRaw($"SELECT * FROM Users WHERE Name = '{name}'") → 危险,C# 层已拼接完成,'admin' OR 1=1 -- 直接进 SQLFromSqlRaw("SELECT * FROM Users WHERE Name = " + name) → 同样危险,字符串拼接早于 EF 执行FromSqlRaw("WHERE Status = {0}", "Active") → 安全,EF 将 {0} 视为参数占位符,走绑定机制FromSqlRaw("WHERE Name = @name", new SqlParameter("@name", name)) → 安全,显式构造参数对象FromSqlInterpolated 看似省事,但有硬限制它确实能自动参数化插值变量,但只认纯变量引用,不处理表达式或拼接逻辑。
context.Users.FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {name}") → 安全context.Users.FromSqlInterpolated($"SELECT * FROM Users WHERE CreatedAt > {DateTime.UtcNow.AddDays(-7)}") → 安全context.Users.FromSqlInterpolated($"SELECT * FROM Users WHERE Name LIKE {name + "%"}") → 危险,name + "%" 是 C# 表达式,结果整体当参数,语义错乱context.Users.FromSqlInterpolated($"SELECT * FROM Users WHERE {whereClause}") → 完全无效,whereClause 是字符串变量,会被整个当参数值,WHERE 条件消失数据库引擎不支持参数化标识符(identifier),FromSqlRaw("SELECT * FROM {0}", tableName) 在语法上就非法,EF 也不会帮你校验或转义。
new[] { "Users", "Orders", "Products" } 中的值if (!new[] { "Name", "Email", "CreatedAt" }.Contains(sortField)) throw ...;if (sortDir != "ASC" && sortDir != "DESC") throw ...
string.Concat、StringBuilder 或 Replace “过滤关键词”来糊弄——"or" 被删了,"oR" 或换行绕过照样生效真正麻烦的不是写对那几行参数化代码,而是得时刻分清“数据”和“结构”:值可以参数化,SQL 骨架必须靠白名单兜底。漏掉任何一个动态拼接点,整条链路就失效。