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);
- ✓所有外部值都用 setParameter() 或 DBAL 占位符绑定;不要拼接到 DQL 或 SQL。
- ✓将 QueryBuilder 表达式方法和 DQL 片段视为代码。对字段、排序方向、运算符和函数使用允许列表。
- ✓原生 SQL 使用带占位符的 executeQuery($sql, $params) 或 executeStatement($sql, $params)。
- ✓同时审查数据流和查询结构。参数化值仍可能暴露未授权记录;授权检查需要单独执行。
如何检查代码库
rg -n -g '*.php' 'createQuery\(|orderBy\(|addOrderBy\(|executeQuery\(' .逐项检查字符串拼接/插值、用户输入进入表达式 API,以及未通过固定列表选择的标识符。搜索结果是审查线索,不等于可利用性的证明。