flawopen.com/SQL 注入/Javascript

SQL 注入 in Javascript

严重 CWE-89 Draft — pending review
Language: English Português (Brasil) Español Français Deutsch Русский 简体中文 日本語 हिन्दी 한국어 Bahasa Indonesia
通俗解释 (ELI5)

想象一个只接收取件码的窗口。SQL 注入就是有人在输入框里输入了一段特殊指令,导致系统把所有人的快递信息全倒了出来,因为系统根本没验证输入是不是合法数字。

核心概念
模板字符串 (Template Literal)
使用反引号 (`...`) 包含 ${var} 的语法。直接用于拼接 SQL 时与危险的字符串相加完全等价。
参数占位符
如 ? 或 $1,指示数据库驱动在协议层单独绑定数据。

原理解析

当未经校验的用户输入被直接拼接到 SQL 查询语句中时,攻击者可以通过输入闭合原有语句并执行未授权指令。在 Node.js 中,模板字符串是最常见的隐蔽注入源头。

真实安全事件

2015 年英国电信巨头 TalkTalk 因遗留系统中的 SQL 注入漏洞被黑客窃取 15 万用户隐私,监管机构处以 40 万英镑巨额罚款。

数据来源:英国信息专员办公室 (ICO) 处罚裁决,2016 年。

缺陷代码 vs 修复方案

VULNERABLE
// userId comes straight from request query
async function getUser(pool, userId) {
  const query = `SELECT * FROM users
    WHERE id = ${userId}`;
  const [rows] = await pool.query(query);
  return rows[0];
}
FIXED
// value is passed separately, never inlined
async function getUser(pool, userId) {
  const [rows] = await pool.query(
    'SELECT * FROM users WHERE id = ?',
    [userId]
  );
  return rows[0];
}

修复原理

参数化查询将 SQL 骨架与参数数据分开发送给数据库,数据库在执行前已完成语法树解析,用户输入绝不可能被当作 SQL 指令执行。

语言专属陷阱

不同驱动占位符语法差异

mysql2 使用 ? 占位符,而 pg (PostgreSQL) 使用 $1, $2。混用会导致语法报错或参数未正确绑定。

Prisma 的 $queryRawUnsafe 陷阱

普通 $queryRaw 会自动参数化,但一旦使用 $queryRawUnsafe 并拼接字符串,安全防护立刻失效。

常见认知误区

“前端做了类型校验就安全”

攻击者可以直接绕过前端向后端发送任意 HTTP 请求,必须在后端数据库交互层做参数化。

如何检测与排查

grep -rn "query(\`.*\${" --include="*.js" --include="*.ts" . npx eslint --rule 'no-template-curly-in-string: error' .
Run Semgrep with p/javascript ruleset in CI to catch unparameterized database queries automatically.

防御自查清单

常见问题 (FAQ)

使用 ORM 就高枕无忧了吗?

只有使用 ORM 标准查询构造器才安全;使用 raw()、query() 或原生 SQL 逃逸接口时必须手动参数化。

参考规范

相关漏洞: Cross-Site Scripting Command InjectionPath Traversal