説明
利用者の入力をSQLクエリに直接挿入すると、攻撃者がクエリの構造を変更できる可能性があります。不正なSQLにより、認証の回避や、権限のないデータ閲覧・変更・削除につながるおそれがあります。
想定される影響
- データベースの重要な情報を不正に閲覧、変更、削除される可能性があります。
- ログインや権限確認のクエリを操作され、アクセス制御を回避されるおそれがあります。
- 破壊的なクエリやデータベース構造の変更で、サービスが停止する可能性があります。
対処方法
- クエリの値にはパラメーターバインドやprepared statementを使ってください。
- 利用者の入力をSQL文字列に直接挿入しないでください。
- ORMでも値をバインドするクエリメソッドを使ってください。
- 入力の形式、長さ、許可する値を検証し、想定外の入力を拒否してください。
例
connは事前に用意したMySQL2のPromise接続またはプールです。接続の作成、エラー処理、リクエストごとのアクセス権限の確認は省略しています。
変更前
javascript
const mysql = require('mysql2');
async function getUserById(req, res) {
let userId = req.query.userId;
let sql = "SELECT * FROM users WHERE id = " + userId; // 入力をSQLに直接挿入
const [rows, fields] = await conn.execute(sql);
res.json(rows);
}
変更後
javascript
const mysql = require('mysql2');
async function getUserById(req, res) {
let userId = req.query.userId;
// 値をパラメーターとしてバインド
const [rows, fields] = await conn.execute(
"SELECT * FROM users WHERE id = ?", [userId]
);
res.json(rows);
}
変更前はuserIdをSQLに連結するため、クエリを操作される可能性があります。変更後はexecuteに固定のSQLと値の配列を別々に渡し、prepared statementの?に値をバインドします。値はSQL構文と区別して処理されます。入力の検証と、その利用者のデータにアクセスする権限は別途確認してください。