flawopen.com/JavaScript の SQL Injection/Prisma
Prisma $queryRaw は SQL Injection に安全?
リファレンスガイド
要点
クエリパラメーターは、SQL フォームに封印された値欄のようなものです。データベースは値を構文ではなくデータとして扱います。$queryRaw の tagged template は補間値をバインドします。placeholder と引数を分けて渡せば $queryRawUnsafe でも値をバインドできますが、信頼できない文字列を連結して SQL を作ると危険です。どちらの方法もテーブル名や列名はパラメーター化できません。
危険 — 入力値を SQL に連結
const userId = request.query.userId;
const query =
`SELECT id FROM users WHERE id = ${userId}`;
const rows = await prisma.$queryRawUnsafe(query);
強化 — 値をバインドし SQL 構造は allowlist で限定
const rows = await prisma.$queryRaw`
SELECT id FROM users WHERE id = ${userId}
`;
// PostgreSQL example: $1 binds data, not an identifier.
const columns = { name: 'name', created: 'created_at' } as const;
const column = columns[requestedSort as keyof typeof columns] ?? 'created_at';
const pageSize = 25;
const sortedRows = await prisma.$queryRawUnsafe(
`SELECT id FROM users ORDER BY ${column} LIMIT $1`,
pageSize
);
// The selected SQL structure comes from a fixed map.
Prisma のパラメーターでできることと限界
$queryRaw では tagged template の呼び出しを直接使います。補間値はそれぞれデータベースパラメーターになります。SQL 文字列を先に作り、それだけを引数に渡してはいけません。Prisma は $queryRawUnsafe(query, ...values) の placeholder もサポートしており、値をバインドできますが SQL テキスト自体は信頼できる必要があります。パラメーターはデータ値用で、識別子、演算子、SQL 断片には使えません。選択可能な列はアプリケーション管理の固定 allowlist に対応付けます。多くの型安全な raw クエリ用途では Prisma は TypedSQL を推奨しています。
Prisma raw クエリの監査方法
grep -rn "\$queryRawUnsafe\|\$executeRawUnsafe" --include="*.ts" --include="*.js" .よくある質問
$queryRawUnsafe はなぜ存在するのですか?
raw SQL 文字列を受け取り、値を別引数で渡す placeholder にも対応するためです。柔軟な分、危険な文字列生成を招きやすいので SQL と引数を一緒に確認します。動的識別子が安全になるわけではありません。固定 allowlist から選んでください。