説明
文字列連結やテンプレートリテラルで外部入力をSQLに直接組み込むと、攻撃者がクエリを変更できる可能性があります。不正な閲覧や変更につながり、影響範囲はデータベースアカウントの権限と設定に左右されます。
想定される影響
- パスワードなどの機密情報が漏えいするおそれがあります。
- データを不正に追加、変更、削除される可能性があります。
- 不正なクエリでデータベースやアプリケーションが停止するおそれがあります。
対処方法
- 利用者の入力をSQLへ直接挿入せず、パラメーターとしてバインドしてください。
- 入力の型、長さ、許可する文字を検証してください。
- 値としてバインドできない動的なテーブル名や列名は、固定の許可リストから選んでください。
例
変更前
javascript
const express = require('express');
const mssql = require('mssql');
app.get('/user', async (req, res) => {
const id = req.query.id;
const pool = mssql.connect(/* config */);
const request = (await pool).request();
// 利用者の入力をクエリに直接挿入
const result = await request.query(`SELECT * FROM users WHERE id = ${id}`);
res.json(result);
});
変更後
javascript
const express = require('express');
const mssql = require('mssql');
app.get('/user', async (req, res) => {
const id = parseInt(req.query.id, 10); // 整数変換の例: 入力は別途検証する
const pool = mssql.connect(/* config */);
const request = (await pool).request();
// 値をパラメーターとしてバインド
request.input('userId', mssql.Int, id);
const result = await request.query('SELECT * FROM users WHERE id = @userId');
res.json(result);
});
変更前はidをクエリに直接挿入し、接続アカウントの権限内で意味を変えられる可能性があります。変更後は@userIdに値をバインドし、SQL構文と分離します。parseIntは厳密な入力検証ではありません。入力全体の形式、NaN、SQLのIntの範囲、リクエスト元のアクセス権限を確認してください。接続設定とエラー処理は省略しています。