mysql – PHP で SQL インジェクションを防ぐにはどうすればよいですか?

プログラミングQA

[ad_1]

多くの有用な回答について、このスレッドに何らかの価値を追加したいと考えています。

SQL インジェクションは、ユーザー入力 (ユーザーによって入力され、クエリ内で使用される入力) を通じて実行できる攻撃です。 SQL インジェクション パターンは正しいクエリ構文ですが、それを呼ぶこともできます: 悪い理由による悪いクエリであり、セキュリティの 3 つの原則 (機密性) に影響を与える秘密情報を取得しようとする (アクセス制御をバイパスする) 悪い人物が存在する可能性があると想定しています。 、整合性、および可用性)。

さて、私たちのポイントは、SQL インジェクション攻撃などのセキュリティの脅威を防ぐことです。質問 (PHP を使用して SQL インジェクション攻撃を防ぐ方法)、より現実的であること、データのフィルタリングまたは入力データのクリアは、内部でユーザー入力データを使用する場合です。 PHP やその他のプログラミング言語を使用したそのようなクエリは当てはまりません。または、プリペアド ステートメントなどの最新のテクノロジや、現在 SQL インジェクション防止をサポートしているその他のツールを使用することをより多くの人が推奨しているように、これらのツールはもう利用できないと考えてください。 アプリケーションをどのように保護しますか?

SQL インジェクションに対する私のアプローチは、ユーザー入力データをデータベースに送信する前に (クエリ内で使用する前に) クリアすることです。

データのフィルタリング (安全でないデータを安全なデータに変換する)

それを考慮してください PDOMySQLi 利用できません。 アプリケーションをどのように保護できますか? それらを使用するように強制しますか? PHP以外の言語はどうですか? 特定の言語だけでなく、より広い境界線に使用できるため、一般的なアイデアを提供することを好みます。

  1. SQL ユーザー (ユーザー特権の制限): 最も一般的な SQL 操作は (SELECT、UPDATE、INSERT) です。では、UPDATE 特権を必要としないユーザーになぜ UPDATE 特権を与えるのでしょうか? 例えば、 ログイン、検索ページ SELECTのみを使用しているのに、なぜこれらのページで高い権限を持つDBユーザーを使用するのでしょうか?

ルール: すべての権限に対して 1 つのデータベース ユーザーを作成しないでください。 すべての SQL 操作で、(deluser、selectuser、updateuser) などのスキームをユーザー名として簡単に作成できます。

見る 最小特権の原則.

  1. データのフィルタリング: クエリのユーザー入力を作成する前に、検証してフィルタリングする必要があります。 プログラマーにとって、ユーザー入力変数ごとにいくつかのプロパティを定義することが重要です。
    データ型、データパターン、データ長. (x と y) の間の数値であるフィールドは、正確なルールを使用して正確に検証する必要があり、文字列 (テキスト) であるフィールドの場合: パターンが該当します。たとえば、ユーザー名にはいくつかの文字のみを含める必要があります。いう [a-zA-Z0-9_-.]. 長さは (x と n) の間で変化します。ここで、x と n (整数、x <=n) です。 ルール: 正確なフィルターと検証ルールを作成することは、私にとってベスト プラクティスです。

  2. 他のツールを使用する: ここでは、準備済みステートメント (パラメーター化されたクエリ) とストアド プロシージャについても同意します。 ここでの欠点は、これらの方法には、ほとんどのユーザーには存在しない高度なスキルが必要なことです。 ここでの基本的な考え方は、SQL クエリと内部で使用されるデータを区別することです。 ここでのユーザー入力データは、(any または x=x) などの元のクエリに何も追加しないため、安全でないデータでも両方のアプローチを使用できます。

詳細については、お読みください OWASP SQL インジェクション防止チート シート.

さて、あなたが上級ユーザーなら、この防御策を好きなように使い始めてください。しかし、初心者で、ストアド プロシージャをすぐに実装してステートメントを準備できない場合は、入力データをできるだけフィルタリングすることをお勧めします。

最後に、ユーザーがユーザー名を入力する代わりに、以下のテキストを送信したとします。

[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User="root"

この入力は、プリペアド ステートメントやストアド プロシージャを使用せずに早い段階でチェックできますが、念のため、これらの使用はユーザー データのフィルタリングと検証の後に開始します。

最後のポイントは、より多くの労力と複雑さを必要とする予期しない動作の検出です。 通常の Web アプリケーションにはお勧めしません。

上記のユーザー入力で予期しない動作が発生するのは、SELECT、UNION、IF、SUBSTRING、BENCHMARK、SHA、および root です。 これらの単語が検出されたら、入力を避けることができます。

更新 1:

ユーザーがこの投稿は役に立たないとコメントしました。OK! これは何ですか OWASP.ORG提供:

主な防御:

オプション #1: 準備済みステートメント (パラメーター化されたクエリ) の使用
オプション #2: ストアド プロシージャの使用
オプション #3: すべてのユーザー提供の入力をエスケープする

追加の防御:

強制: 最小限の権限
また実行: ホワイトリストの入力検証

ご存知かもしれませんが、論文の主張は有効な議論、少なくとも 1 つの参考文献によって裏付けられる必要があります。 そうでなければ、それは攻撃と悪い主張と見なされます!

更新 2:

PHPのマニュアルから、 PHP: プリペアド ステートメント – マニュアル:

エスケープと SQL インジェクション

バインドされた変数は、サーバーによって自動的にエスケープされます。 サーバーは、エスケープされた値を実行前にステートメント テンプレートの適切な場所に挿入します。 適切な変換を作成するには、バインドされた変数の型のヒントをサーバーに提供する必要があります。 詳細については、mysqli_stmt_bind_param() 関数を参照してください。

サーバー内での値の自動エスケープは、SQL インジェクションを防ぐためのセキュリティ機能と見なされることがあります。 入力値が正しくエスケープされていれば、準備されていないステートメントでも同じ程度のセキュリティを実現できます。

更新 3:

PDO と MySQLi がプリペアド ステートメントを使用して MySQL サーバーにクエリを送信する方法を知るためのテスト ケースを作成しました。

PDO:

$user = "''1''"; // Malicious keyword
$sql="SELECT * FROM awa_user WHERE userame =:username";
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));

クエリ ログ:

    189 Query SELECT * FROM awa_user WHERE userame="\"\'1\'\''
    189 Quit

MySQL:

$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();

クエリ ログ:

    188 Prepare   SELECT * FROM awa_user WHERE username =?
    188 Execute   SELECT * FROM awa_user WHERE username="\"\'1\'\''
    188 Quit

準備されたステートメントもデータをエスケープしていることは明らかです。

上記の発言にもあるように、

サーバー内での値の自動エスケープは、SQL インジェクションを防ぐためのセキュリティ機能と見なされることがあります。 入力値が正しくエスケープされている場合、準備されていないステートメントでも同じ程度のセキュリティを実現できます

したがって、これは、次のようなデータ検証が証明されています。 intval() クエリを送信する前に整数値を使用することをお勧めします。 さらに、クエリを送信する前に悪意のあるユーザー データを防止することは、 正しく有効なアプローチ.

詳細については、この質問を参照してください。 PDO は生のクエリを MySQL に送信し、Mysqli は準備されたクエリを送信しますが、どちらも同じ結果を生成します

参考文献:

  1. SQL インジェクションチートシート
  2. SQL インジェクション
  3. 情報セキュリティー
  4. セキュリティ原則
  5. データ検証

[ad_2]

Source link

コメント

タイトルとURLをコピーしました