web-dev-qa-db-ja.com

文字と数字を使用したSQLインジェクション

ハッカーが文字と数字だけを使用してSQLインジェクション攻撃を実行することがまったく可能かどうか疑問に思っていました。たとえば、組み込みのPHP関数の代わりに正規表現を使用するこのPHPコードを見てみましょう。

<?php
$id = preg_replace('/[^a-zA-Z0-9]/', '', $_GET['id']);
$result = $mysqli->query("SELECT * users WHERE id = '".$id."'");

コードが何をするのか疑問に思われる場合は、文字や数字以外のすべての文字を削除し、MySQLでそのクエリを実行します。ハッカーがそのコードを何らかの方法で悪用できるかどうか疑問に思っていましたが、そうでない場合、それとmysqli::prepareまたはmysqli::escape_stringの違いは何でしょうか?

8
ub3rst4r

MySQL文字列リテラル コンテキストに$id値が挿入され、任意のSQLフラグメントを提供することが可能である場合にのみ、セキュリティ上の欠陥があります。そして、これは、$idに、MySQL文字列リテラルの終了区切り文字を示すプレーンな'が含まれている場合にのみ可能です。

// resulting SQL statement with $id = "' OR '1'='1"
SELECT * users WHERE id = '' OR '1'='1'

ここで、'から$id文字を削除するため、文字列リテラルコンテキストを離れることはできず、したがって任意のSQLフラグメントを提供することはできません。

ただし、この結論は、値がMySQL文字列リテラルで使用される場合にのみ適用されます。別のクエリの値に対して同じ入力フィルタリングを使用している場合でも、SQLインジェクションに対して脆弱である可能性があります。

つまり、mysqli::preparemysqli::escape_stringなどのメソッドは適切な緩和手法です。 mysqli::prepare は、いわゆるパラメーター化されたステートメント/クエリを実装します 準備されたステートメント ここで、コマンド(SQLステートメント)とユーザー提供のデータは互いに分離されているため、ユーザーは提供されたデータを誤ってコマンドとして解釈することはできません。 mysqli::escape_string は、データの特定の文字をエスケープするだけで、文字列リテラルの終了区切り文字のような制御文字と混同されないため、現在の手法に似ています。

9
Gumbo

(私はこれをコメントとして投稿しますが、コメントはリンクをきちんと行いません)。

これはスタックオーバーフローでは similar から manyquestions へとかなり変わります。

Open Web Application Security Project(OWASP) 注意事項 その 特殊文字のエスケープ は、SQLインジェクションに対する防御策です。

  1. 準備済みステートメント(パラメーター化されたクエリ)とストアドプロシージャを使用する
  2. Ifパラメータ化されたAPIが利用できない...特殊文字をエスケープする
  3. ホワイトリスト入力検証を実行する

特殊文字なしでSQLiを実現する概念実証コードに関する限り、私は何も見ていませんが、証拠がないことは、存在しないという証拠ではありません。パラメーター化されたクエリを実装できる場合は、実装しないでください。

3
scuzzy-delta

一般的な経験則:車輪を再発明しないでください!

あなたが提供したコードはおそらく悪用可能ではありませんが、可能な限り、準備されたステートメントを使用するいくつかの正当な理由があります(優れた 永続フレームワーク はさらに優れています)。

  • 準備されたステートメントは 効率的
  • 正規表現エンジンにエキゾチックキャラクターをフィードした場合に起こりうる結果をすべて処理する必要はありません( mysql_escape_string() fiascoを参照)。
  • 前のポイントに関連して:ユーザーデータが重要な方法で格納/エンコード/フォーマットされている場合 SQLスマグリング が可能かもしれません
  • この例では、防御は2つのフェーズで実装されています。REとSQL式の両方を、他のコンポーネントを考慮して調整する必要があります。コードベースが成長し始めると(そしておそらく他の開発者も加わるように)、両方のステップを常に処理することは困難であり、遅かれ早かれ悪用可能な間違いを犯すことになります
3
buherator

SQLインジェクションはMySQLの16進リテラルのサポートであり、投票テーブルのid列が文字列型であるという事実は次のようになります。

文字列コンテキストでは、これらはバイナリ文字列のように機能し、16進数の各ペアが文字に変換されます。

mysql> SELECT 0x0f+0;
    -> 15

PHP 0x…は数値(is_numeric)であり、MySQLの場合0x…は文字列として解釈および保存され、後で上記のSELECTステートメントに挿入されます。

これは、次の場合には不可能です。

idは数値データ型、またはSELECTは準備済みステートメントでした。

したがって、0x [0-9a-f] .....で始まる16進エンコードされたペイロードを挿入するために使用できる0-9およびa-zを許可しているため、16進エンコードされたペイロードが通過する可能性があります。

0
Aayush