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文字列の組み立てに使うと文字列連結と同じ脆弱性を引き起こします。

何が起きているか

ユーザー入力をそのままSQL文字列に結合すると、意図しないSQL構文が実行されます。Node.jsでは日常的に使われるテンプレートリテラルが最大の原因です。

実際の被害事例

英大手通信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];
}

なぜ対策コードで防げるのか

プレースホルダーを用いることで、DBエンジンが構文木を確定させた後にパラメータ値だけを安全にバインドします。

言語固有の落とし穴

ドライバーによるプレースホルダー記法の違い

mysql2は「?」を使用しますが、PostgreSQL用のpgは「$1, $2」を使用します。

よくある誤解

「シングルクォートを自前で置換すれば安全」

エンコーディングの違いによるバイパスが存在するため、パラメータ化クエリのみが確実な対策です。

影響の有無を確認する方法

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)

PrismaやTypeORMを使えば安全ですか?

標準APIは安全ですが、$queryRawUnsafeや生のSQL実行メソッドでは自前でバインドする必要があります。

参考資料

関連する脆弱性: Cross-Site Scripting Command InjectionPath Traversal