Shikata Ga Nai

Private? There is no such things.

隠されたデータの取得 - SQLインジェクション(続編)

Hello there, ('ω')ノ

SQLインジェクションの基本的な概念を理解したところで、今回は コメントアウト(--)を利用した攻撃OR 1=1 を使った全データ取得 について詳しく解説します。これらの手法を理解することで、より高度なSQLi攻撃の検出と防御が可能になります。


1. コメントアウト(--)を利用したSQLインジェクション

脆弱なアプリケーションの挙動

あるショッピングサイトでは、次のURLを使用して特定のカテゴリの商品を表示しています。

https://insecure-website.com/products?category=Gifts

このリクエストによって、次のSQLクエリが実行されます。

SELECT * FROM products WHERE category = 'Gifts' AND released = 1;

この released = 1 という条件は、「未発売の商品」を隠すために追加されています。

攻撃方法:コメントアウトを利用する

攻撃者は、次のように -- を使用して released = 1 を無効化できます。

https://insecure-website.com/products?category=Gifts'--

このリクエストによって、次のようなSQLクエリに変化します。

SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1;

ここで -- はSQLのコメント記号 なので、AND released = 1 の部分は無視され、クエリは WHERE category = 'Gifts' だけが適用 されるようになります。

結果: 未発売の商品 (released = 0) もすべて表示されてしまう。


2. OR 1=1 を利用してすべての商品を取得

-- を使うだけでなく、攻撃者は OR 1=1 を加えることで、より広範囲のデータを取得できます。

攻撃例:OR 1=1 を使用

https://insecure-website.com/products?category=Gifts' OR 1=1--

このリクエストにより、以下のSQLクエリが実行されます。

SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1;

1=1 は常に真 なので、このクエリは すべての商品を取得 するようになります。

結果: 全カテゴリの商品が表示される(攻撃者はどんなカテゴリがあるのか知らなくても、すべての商品を取得可能)。


3. OR 1=1 の危険性

攻撃者が OR 1=1 を使用すると、思わぬデータ破壊 を引き起こす可能性があります。

例えば、アプリケーションが同じリクエストパラメータを UPDATEDELETE 文にも使っていた場合、次のような影響が発生します。

DELETE 文に影響を与える例

DELETE FROM products WHERE category = 'Gifts' OR 1=1;

結果: OR 1=1 によって すべての商品が削除されてしまう

💡 重要: 攻撃を試す際は、対象のクエリが SELECT だけではなく、UPDATEDELETE にも影響を及ぼさないか慎重に確認する必要があります。


4. SQLインジェクションを防ぐ方法

このような攻撃を防ぐには、以下の対策を徹底する必要があります。

1. プリペアドステートメントの使用(最優先)

SQLインジェクションを確実に防ぐためには、プリペアドステートメント(バインド変数) を使用するのが最も効果的です。

安全なコード例(PHP + PDO)

$stmt = $pdo->prepare("SELECT * FROM products WHERE category = ? AND released = 1");
$stmt->execute([$category]);

この方法では、ユーザーの入力値がSQLクエリに直接埋め込まれることがないため、安全に処理されます。


2. ユーザー入力のバリデーション

  • category パラメータは 許可リスト(ホワイトリスト) を使って制限する。
  • 例えば、categoryGifts, Electronics, Clothing などのリスト内にあるかどうかチェックする。

許可リストの実装(PHP)

$allowed_categories = ['Gifts', 'Electronics', 'Clothing'];
if (!in_array($category, $allowed_categories)) {
    die("Invalid category");
}

3. SQLエラーメッセージを非表示にする

  • データベースのエラーメッセージをそのまま表示しない。
  • 500 Internal Server Error などの一般的なエラーメッセージを返す。

安全なエラーハンドリング(PHP)

try {
    $stmt = $pdo->prepare("SELECT * FROM products WHERE category = ? AND released = 1");
    $stmt->execute([$category]);
} catch (Exception $e) {
    error_log($e->getMessage());
    die("An error occurred.");
}

4. データベースの権限を最小限にする

  • アプリケーションのDBユーザーには、SELECT 権限のみを付与し、DELETEUPDATE の権限を制限する。

安全な権限設定(MySQL)

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

まとめ

🎯 攻撃手法のポイント
1. -- を利用して AND released = 1 の部分をコメントアウトし、隠されたデータを取得
2. OR 1=1 を追加して、データベース内のすべてのデータを取得
3. OR 1=1DELETE 文や UPDATE 文に影響を与えると、すべてのデータが削除される危険性がある

🛡 防御策(必ず実装すること!)
プリペアドステートメントを使用する(最優先)
ユーザー入力を許可リストで制限する
エラーメッセージを非表示にする
データベースの権限を最小限にする

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

Best regards, (^^ゞ