Shikata Ga Nai

Private? There is no such things.

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

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 パラメータが 許可された値のみ を受け付けるようにする。
  • 例えば、categoryElectronics, Gifts, Clothing などのリストから選択させる。

許可リストを使用する例(PHP):

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

3. エラーメッセージを抑制する

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

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

  • アプリケーションが使用するデータベースユーザーには、読み取り専用の権限(SELECTのみ)を付与 する。
  • DROPUPDATE などの権限を不要にする。

安全な権限設定(MySQL):

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

まとめ

🔍 隠されたデータを取得するSQLインジェクション攻撃の手法:
1. OR 1=1 を使って WHERE 句の制限を回避
2. UNION SELECT を使って他のテーブルのデータを取得
3. エラーメッセージを利用 してデータベースの情報を引き出す

🛡 防御策:
プリペアドステートメントを使用する(最優先)
入力値を許可リストで制限する
エラーメッセージを抑制する
データベースの権限を最小限にする

SQLインジェクションは、入力値を適切に処理することで確実に防ぐことができます。開発時にこれらの対策を徹底し、安全なアプリケーションを構築しましょう。

Best regards, (^^ゞ