Shikata Ga Nai

Private? There is no such things.

SQLインジェクションによるアプリケーションのロジック回避

Hello there, ('ω')ノ

SQLインジェクションを利用すると、認証を回避し、パスワードなしで管理者アカウントにログインすることが可能になります。この攻撃手法は、「アプリケーションのロジックを破壊する」 という点で非常に危険です。


🛠️ 攻撃対象の認証処理

通常、アプリケーションは次のようなSQLクエリを実行して、入力された ユーザー名とパスワード が正しいかをチェックします。

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese';

このクエリが 一致するレコードを返せばログイン成功 となります。

しかし、SQLインジェクションを使うことで、このチェックをバイパスできます。


🎯 SQLインジェクションによる認証回避

攻撃者はログインフォームに次のような入力を行います。

  • ユーザー名: administrator'--
  • パスワード: (空欄)

これにより、アプリケーションが次のようなSQLクエリを実行することになります。

SELECT * FROM users WHERE username = 'administrator'--' AND password = '';

💡 -- はSQLのコメントアウト記号 なので、AND password = '' の部分は無視され、クエリは次のように処理されます。

SELECT * FROM users WHERE username = 'administrator';

もし administrator というユーザーがデータベースに存在すれば、パスワードが不要でもログインが成功してしまう わけです。

結果: 攻撃者は パスワードを知らなくても管理者アカウントにログイン可能 になる。


🚀 別の攻撃方法:OR 1=1 を利用した認証バイパス

攻撃者は、次のような入力を使って、どんなユーザー名でもログインできるようにすることも可能です。

  • ユーザー名: ' OR 1=1--
  • パスワード: (空欄)

この場合、SQLクエリは次のように変わります。

SELECT * FROM users WHERE username = '' OR 1=1--' AND password = '';

1=1 は常に なので、このクエリは データベース内のすべてのユーザー情報を取得 し、最初に見つかったユーザーとしてログインすることになります。

結果: どのアカウントにもパスワードなしでログインできる。


🔒 防御策(SQLインジェクションを防ぐ方法)

このようなSQLインジェクション攻撃を防ぐためには、以下の対策が必要です。

1️⃣ プリペアドステートメントを使用する(最重要)

ユーザー入力を直接SQLクエリに組み込まず、バインド変数 を使用することで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 のみ許可し、DROPUPDATE は制限する。

安全な権限設定(MySQL)

GRANT SELECT ON shop.users TO 'app_user'@'localhost';

✅ まとめ

🎯 攻撃手法のポイント
1. administrator'-- を入力することで、パスワードなしで管理者アカウントにログイン
2. ' OR 1=1-- を入力することで、どのアカウントにもログイン可能

🛡 防御策(必ず実装すること!)
プリペアドステートメントを使用する(最優先)
ユーザー入力のバリデーションを行う(特殊文字をブロック)
エラーメッセージを適切に処理する(SQLエラーを表示しない)
データベースの権限を最小限にする(SELECT のみ許可)

SQLインジェクションは、適切な対策を講じることで確実に防ぐことが可能 です。開発の際には、常に 「このコードはSQLiに対して安全か?」 を意識し、安全なアプリケーションを構築しましょう!

Best regards, (^^ゞ