私の友人が、私が楽しんでテストしているWebアプリケーションを作成しました。私は彼がユーザーに特定のクエリの制限を設定することを許可していることに気づき、その制限は無害化されていません。
たとえば、制限として好きな数字や文字列を選択できます。これは SQLインジェクション であり、SQLコマンドを簡単にインジェクトできますが、LIMIT
を使用してデータを抽出したり、損傷を与えることは本当に可能ですか?
クエリの例:
SELECT * FROM messages WHERE unread = 1 LIMIT **USER INPUT HERE**
インジェクションがWHERE
句にある場合、UNION SELECT
を実行して情報を抽出することは簡単だったと思いますが、ユーザー入力が制限を超えていれば、本当に可能ですか?
詳細については、私の友人は MySQL DBMSを使用しているため、次のような2つのクエリを実際に実行することはできません。
SELECT * FROM messages WHERE unread = 1 LIMIT 10;DROP TABLE messages--
それは不可能。
ここでUNION SELECT
を作成できます。唯一の問題はメッセージの列を一致させることですが、収まるまで列を追加することでそれらを推測できます。
SELECT * FROM messages WHERE unread = 1 LIMIT
1 UNION SELECT mail,password,1,1,1 FROM users
正しい列数が得られるまで,1
を追加してください。また、列タイプを一致させる必要があります。 1
ではなくnull
を試してください。
ここでMySQLのエラーが表示されると、大きな助けになります。それ以外の場合は、多くの試みをしました。
詳細については、owasp.orgのSQLインジェクションのテストも参照してください。
制約はほとんどなく、通常の方法で実行できます(UNIONまたは '; XXX ---')
場合によっては不可能であり、ブール式をLIMITに置く必要があります。これはブラインドSQLインジェクションであり、データベース全体を一度に1ビットずつダンプできます。
MySQLは複数のステートメントをサポートします で、少なくとも4.1年から10年前に使用しています。たとえば、 Perl mysqlモジュールでmysql_multi_statements
を使用してこれをオンにする ができます。
クライアントライブラリは現在複数のステートメントをサポートしていない可能性がありますが、セキュリティホールから離れたアップグレードまたは構成の変更にすぎません。
これは、PDOの準備済みステートメントとその変数を整数のみの入力としてbindParamを使用するのに良いタイミングです。これにより、SQLを挿入して実行しようとしていることをすべて無効にすることができます。
また、ユーザーがドロップダウンの数値の事前設定リストから選択できるようにすることも検討します。結果ページがページ分割に設定されていない限り、ページに100,000件のレコードを読み込もうとすると、手ごわいことが起こります。
友人のクエリは今日はあまり役に立ちませんが、後であるかもしれませんが、テクノロジーが進化し、MySQL DBMSは他の多くのテクノロジーと同様に常に改善されているため、LIMIT
ステートメントは、その直後にUNION
を使用できるように変更されます。あなたの友人は、MySQL DBMSのアーキテクチャが、現在とは異なり複数のSQLステートメントを実行できるように変更される場合についても検討します。
私が言いたいのは、あなたの友人が入力をサニタイズしなければならないということです。それはベストプラクティスです。今日はあまり重要ではないかもしれませんが、将来、あなたは決して知らないでしょう。あなたの友達。
1 UNION SELECT ...
の制限を設定すると、列が最初のCAST
の列と同じ数と型を持っている(またはSELECT
にできる)限り、攻撃者は他のテーブルから情報を引き出すことができます。制限をsub_SELECT
から生成された値として設定すると、攻撃者は返された行の数からデータベース内の他の情報を読み取ることができます。たとえば、別のユーザーのパスワードハッシュは、異なるサブストリングオフセットで0〜15の数値を返すサブクエリを繰り返し実行し、各結果の行をカウントすることで、一度に4ビット抽出できます。
しかし、これらの攻撃はどちらも阻止できます。多くのデータベースドライバは パラメータ化されたLIMIT
を許可します。特定のドライバーがパラメーター化されたLIMIT
に干渉する場合は、入力を整数に変換してからクエリに文字列置換することで、入力を無害化できます。これは、アプリケーションが1つのクエリ(LIMIT 12345678
など)から処理できる以上のレコードを返さないようにするのにも役立ちます。 PHPでは、次のようになります。
<?php
//...
$limit = intval($_REQUEST['numresults']);
$limit = min(max($limit, 10), 100);
$stmt = $dbh->prepare("SELECT ... FROM ... WHERE ... LIMIT $limit");