状況
商品一覧を、画面で選んだ列で並べ替える API(DB は SQLite)。sort はクエリ文字列から受け取る。
この並べ替えの安全な直し方は?
const sort = req.query.sort; // 例: "price"const sql = `SELECT id, name, price FROM items ORDER BY ${sort}`;const rows = await db.all(sql);正答
- ORDER BY ? と書き、sort をプレースホルダの値として渡す
- 許可する列名の一覧と照合し、一致したときだけ SQL に入れる
- sort に含まれるシングルクォートを取り除いてから SQL に入れる
- sort の長さを 20 文字以内に制限してから SQL に入れる
解説
プレースホルダで渡せるのは値だけで、列名やテーブル名、ASC / DESC のような SQL の構文の一部は渡せない。ORDER BY ? にすると「'price' という定数」で並べることになり、エラーにならないまま並べ替えが効かなくなる。列名を入力から受け取るときは、price・name など許可する列名の一覧を用意し、一致したときだけその列名を SQL に入れる(一致しなければ既定の列にする)。シングルクォートを取り除いても、ORDER BY の後ろは文字列の中ではないので、クォートを使わない式で書き換えられる。長さの制限も、短い攻撃文字列は防げない。
参考: cheatsheetseries.owasp.org
この問題を含む セキュリティ のテストを制限時間つきで解く
セキュリティクイズへ