FlawOpen

flawopen.com/SQL Injection in PHP/Doctrine ORM

Doctrine ORM 能防止 SQL 注入吗?

Reference page
简短回答

能防止使用绑定参数的 DQL 注入。若通过字符串拼接构造 DQL 或原生 SQL,仍会引入相同风险。

不安全 — 输入成为 DQL 语法
$em->createQuery(
  "SELECT u FROM User u "
  . "WHERE u.id = $userId"
);
安全 — 仅使用可信表达式
$qb->select('u')
  ->from('User', 'u')
  ->where('u.id = :id')
  ->setParameter('id', $userId);

绑定值无法保护查询结构

setParameter() 绑定 DQL 值,Doctrine 会将其转换为与查询文本分离的 SQL 参数。把输入拼接进 createQuery() 会绕过保护。原生 SQL 也一样:Connection::executeQuery() 使用占位符和参数数组时安全;把输入插入 SQL 字符串则不安全。

参数不能代替标识符

占位符表示值,不能代表 DQL 标识符、SQL 列名、表名、运算符或排序方向。ORM 安全文档特别指出,用户输入传入 QueryBuilder 表达式方法仍可能构造可注入的 DQL。表达式应留在可信代码中;用户选择的排序字段和方向必须映射到严格允许列表。

不安全 — 输入成为 DQL 语法
$qb->orderBy(
  'u.' . $request->query->get('sort'),
  $request->query->get('direction')
);
安全 — 仅使用可信表达式
$fields = [
    'name' => 'u.name',
    'created' => 'u.createdAt',
];
$directions = ['asc' => 'ASC', 'desc' => 'DESC'];

$key = (string) $request->query->get('sort', 'name');
$sort = $fields[$key] ?? $fields['name'];
$requestedDirection = strtolower(
    (string) $request->query->get('direction', 'asc')
);
$direction = $directions[$requestedDirection] ?? 'ASC';

$qb->orderBy($sort, $direction);

如何检查代码库

rg -n -g '*.php' 'createQuery\(|orderBy\(|addOrderBy\(|executeQuery\(' .
逐项检查字符串拼接/插值、用户输入进入表达式 API,以及未通过固定列表选择的标识符。搜索结果是审查线索,不等于可利用性的证明。

来源与参考

另请参阅 SQL 注入(CWE-89):原理与各编程语言的防护方法 — flawopen.com EF Core FromSqlRaw:安全参数化 SQL FastAPI SQL 注入:Pydantic 能防什么,不能防什么 GORM Raw SQL:防止 Go 中的 SQL 注入 转义引号足以防止 SQL Injection 吗? 使用 ORM 足以防止 SQL 注入吗? Knex.js 能防止 SQL 注入吗?