flawopen.com/SQL Injection/ORM 够吗?
使用 ORM 足以防止 SQL 注入吗?
参考页面
简短回答
ORM 像一间根据订单表做菜的厨房:常规查询构造器会分开传递数据值。原生 SQL 快捷接口是另一条通道,也有自己的规则。先核实具体 API,再判断插值值是否安全。
不安全 — 用户文本拼入 FromSqlRaw SQL
var sql = $"SELECT * FROM dbo.Blogs WHERE Url = '{url}'";
var rows = await context.Blogs
.FromSqlRaw(sql)
.ToListAsync();
// User text is inserted into SQL before execution.
安全 — 使用 FromSql 绑定插值(EF Core 7+)
var rows = await context.Blogs
.FromSql($"SELECT * FROM dbo.Blogs WHERE Url = {url}")
.ToListAsync();
// EF Core 7+: interpolation becomes a SQL parameter.
这些 API 如何处理值
ORM 查询构造器和原生 SQL API 并非统一的安全边界。官方文档说明了安全绑定值的方法:Django raw(sql, params)、使用独立执行参数的 SQLAlchemy text()、Rails 占位符条件、EF Core 7+ FromSql / FromSqlInterpolated、GORM Raw(sql, args...),以及 Prisma 标签模板 $queryRaw。原生 API 的行为不同:FromSqlRaw 单独接收参数时可安全使用,但把用户文本插入 SQL 字符串则不安全;$queryRawUnsafe 也能单独绑定值,但拼接不可信文本仍然不安全。方法名称本身无法说明值的处理方式。请按 API 文档绑定每个数据值。SQL 标识符和查询结构不能作为参数,应从应用控制的固定允许列表中选择。下方指南说明各 API 的具体约定。
"足够"实际需要什么
- ✓普通值和筛选条件优先使用 ORM 查询构造器。
- ✓使用原生 SQL 时,通过 API 文档规定的参数机制绑定每个值。
- ✓动态标识符只能从应用控制的固定允许列表中选取;参数不能绑定 SQL 结构。
- ✓检查原生查询调用中的字符串拼接、插值及不安全方法变体。
FAQ
原生 SQL 方法一定不安全吗?
不一定。有些原生 SQL API 会绑定单独传入的值,有些安全 API 会把插值值作为参数。EF Core 7+ 的 FromSql 接受插值 FormattableString;FromSqlRaw 需要单独传参。Prisma 的 $queryRawUnsafe 也能绑定值,但不会清理自行拼接的 SQL 文本。请核实具体方法约定,确保不可信值不进入 SQL 结构。