Hello there, ('ω')ノ
多くのWebアプリケーションでは、ユーザーに表示するデータを制限するために特定の条件をSQLクエリに追加しています。例えば、ショッピングサイトでは「未発売の商品」や「管理者専用の商品」などの情報を隠すために released = 1
という条件を加えていることがよくあります。
しかし、SQLインジェクションを利用すると、これらの制限を回避し、隠されたデータを取得することが可能です。
脆弱なショッピングサイトの例
例えば、以下のようなURLがあるとします。
https://insecure-website.com/products?category=Gifts
このリクエストによって、サーバーは次のSQLクエリを実行します。
SELECT * FROM products WHERE category = 'Gifts' AND released = 1;
このクエリは、「Gifts」カテゴリーの商品で、かつ released = 1
(発売済み)のデータのみを取得する仕様になっています。
しかし、もし category
パラメータが適切に処理されていない場合、SQLインジェクションを利用して「未発売の商品」も表示させることができます。
SQLインジェクションを使ったデータ取得
攻撃者は、次のようなペイロードを category
パラメータに挿入することで、released = 1 の制限を回避できます。
https://insecure-website.com/products?category=Gifts' OR 1=1 --
このURLが処理されると、SQLクエリは以下のように変化します。
SELECT * FROM products WHERE category = 'Gifts' OR 1=1 -- ' AND released = 1;
1=1
は常に真となるため、WHERE
句の制約が意味をなさなくなり、テーブル内のすべての商品が取得されます。
✅ 結果: 未発売の商品(released = 0
)も含めて、すべての商品が表示される。
もう一つのアプローチ:UNIONベースのSQLインジェクション
アプリケーションが UNION
を許可している場合、攻撃者は UNION
を利用して隠されたデータを取得できます。
攻撃例
https://insecure-website.com/products?category=Gifts' UNION SELECT NULL, username, password FROM users --
このペイロードによって、商品情報とともに、usersテーブルのユーザー名とパスワード も取得される可能性があります。
✅ 結果: 攻撃者は管理者アカウントの情報などを取得できる可能性がある。
対策方法
このようなSQLインジェクション攻撃を防ぐためには、以下の対策が重要です。
1. プリペアドステートメントを使用する(最優先)
SQLインジェクションを完全に防ぐためには、プリペアドステートメント を使用し、ユーザー入力を適切に処理することが重要です。
✅ 安全なクエリの例(PHP + PDO):
$stmt = $pdo->prepare("SELECT * FROM products WHERE category = ? AND released = 1"); $stmt->execute([$category]);
これにより、ユーザー入力がSQLの構造に影響を与えることがなくなり、安全にクエリを実行できます。
2. ユーザー入力のバリデーション
category
パラメータが 許可された値のみ を受け付けるようにする。- 例えば、
category
はElectronics, Gifts, Clothing
などのリストから選択させる。
✅ 許可リストを使用する例(PHP):
$allowed_categories = ['Electronics', 'Gifts', 'Clothing']; if (!in_array($category, $allowed_categories)) { die("Invalid category"); }
3. エラーメッセージを抑制する
- データベースのエラーメッセージをそのままユーザーに表示しない。
500 Internal Server Error
などの一般的なエラーメッセージを返すようにする。
4. 最小限のデータベース権限を設定する
- アプリケーションが使用するデータベースユーザーには、読み取り専用の権限(SELECTのみ)を付与 する。
DROP
やUPDATE
などの権限を不要にする。
✅ 安全な権限設定(MySQL):
GRANT SELECT ON shop.products TO 'app_user'@'localhost';
まとめ
🔍 隠されたデータを取得するSQLインジェクション攻撃の手法:
1. OR 1=1 を使って WHERE
句の制限を回避
2. UNION SELECT を使って他のテーブルのデータを取得
3. エラーメッセージを利用 してデータベースの情報を引き出す
🛡 防御策:
✅ プリペアドステートメントを使用する(最優先)
✅ 入力値を許可リストで制限する
✅ エラーメッセージを抑制する
✅ データベースの権限を最小限にする
SQLインジェクションは、入力値を適切に処理することで確実に防ぐことができます。開発時にこれらの対策を徹底し、安全なアプリケーションを構築しましょう。
Best regards, (^^ゞ