ホームページ  >  記事  >  バックエンド開発  >  PDO アンチインジェクション原理の分析と注意事項、PDO インジェクション_PHP チュートリアル

PDO アンチインジェクション原理の分析と注意事項、PDO インジェクション_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 10:06:111010ブラウズ

PDO アンチインジェクション原理の分析と注意事項、PDO インジェクション

PDO が合理的かつ正しく使用されている限り、基本的に SQL インジェクションを防止できることは誰もが知っています。この記事は主に次の 2 つの質問に答えます。

なぜ mysql_connect の代わりに PDO を使用するのですか?

なぜ PDO はアンチインジェクションなのですか?

PDO アンチインジェクションを使用する際に特に注意すべきことは何ですか?

1. PDO の使用を優先する必要があるのはなぜですか?

PHP マニュアルには明確に記載されています:

コードをコピーします コードは次のとおりです:
プリペアドステートメントとストアドプロシージャ
より成熟したデータベースの多くは、プリペアド ステートメントの概念をサポートしています。プリペアド ステートメントは、アプリケーションが実行する SQL のコンパイル済みテンプレートの一種と考えることができ、変数パラメーターを使用してカスタマイズできます。主な利点:
クエリを解析 (または準備) する必要があるのは 1 回だけですが、同じまたは異なるパラメーターを使用して複数回実行できます。クエリが準備されると、データベースは複雑なクエリを実行するための計画を分析、コンパイル、最適化します。クエリの実行には十分な時間がかかるため、異なるパラメーターを使用して同じクエリを何度も繰り返す必要がある場合、アプリケーションは分析、コンパイル、最適化のサイクルを繰り返す必要がなくなります。つまり、準備されたステートメントは使用するリソースが少なくなるため、より高速に実行されます。

プリペアド ステートメントのパラメータを引用符で囲む必要はありません。アプリケーションがプリペアド ステートメントのみを使用する場合、開発者は SQL インジェクションが発生しないことを確認できます (ただし、クエリの他の部分が使用されている場合)。エスケープされていない入力で構築されているため、SQL インジェクションは依然として可能です)。



PDO の prepare メソッドを使用しても、主に同じ SQL テンプレートのクエリ パフォーマンスを向上させ、SQL インジェクションを防ぎます

同時にPHPマニュアルに警告メッセージが記載されています

コードをコピーします コードは次のとおりです:
PHP 5.3.6 より前では、この要素はサイレントに無視されていましたが、次の例に示すように、PDO::MYSQL_ATTR_INIT_COMMAND ドライバー オプションを使用して同じ動作を部分的に複製できます。 警告
以下の例のメソッドは、ISO-8859-1 や UTF-8 など、ASCII と同じ下位 7 ビット表現を共有する文字セットでのみ使用できます (UTF-16 など)。または Big5) では、PHP 5.3.6 以降のバージョンで提供される charset オプションを使用する必要があります。



これは、PHP 5.3.6 以前のバージョンでは、DSN の文字セット定義がサポートされていないことを意味し、代わりに、初期 SQL を設定するために PDO::MYSQL_ATTR_INIT_COMMAND を使用する必要があります。これは、一般的に使用される set names gbk コマンドです。
いくつかのプログラムがまだインジェクションを防ぐために addslashes を使用しようとしているのを目にしましたが、これが実際にさらなる問題を引き起こしているとは知りませんでした。詳細については、http://www.lorui.com/addslashes-mysql_escape_string-mysql_real_eascape_string.html を参照してください。

データベースクエリを実行する前に、SQL 内の select、union、... などのキーワードをクリーンアップする方法もあります。このアプローチは明らかに間違った対処方法であり、提出されたテキストに学生組合が含まれている場合、置き換えによって元の内容が改ざんされ、無実の人々が無差別に殺害されることになるため、お勧めできません。

2. PDO が SQL インジェクションを防止できるのはなぜですか?

まず次の PHP コードを見てください:


コードをコピーします

コードは次のとおりです: $pdo = 新しい PDO("mysql:host=192.168.0.1;dbname=test;charset=utf8","root");
$st = $pdo->prepare("select * from info where id =? and name = ?");
$id = 21;
$name = '張三';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
$st->execute();
$st->fetchAll();
?>

環境は以下の通りです

PHP 5.4.7

MySQL プロトコル バージョン 10

MySQL サーバー 5.5.27

PHP と MySQL サーバー間の通信の詳細を徹底的に理解するために、調査用に特別に Wireshark を使用してパケットをキャプチャしました。次に示すように、Wireshak をインストールした後、フィルター条件を tcp.port==3306 に設定しました。

このように、不要な干渉を避けるために、mysql 3306 ポートとの通信データのみが表示されます。

Wireshak は wincap ドライバーに基づいており、ローカル ループバック インターフェイスでのリッスンをサポートしていないことに注意することが重要です (PHP を使用してローカル mysql に接続しても、リッスンすることはできません) 他のマシン (仮想マシン) に接続してください。ブリッジされたネットワークを使用することも可能です) テスト用の MySQL。

次に、PHP プログラムを実行します。リスニング結果は次のとおりです。PHP は単に SQL を MySQL サーバーに直接送信しているだけであることがわかりました。

実際、これは mysql_real_escape_string を使用して文字列をエスケープし、SQL ステートメントに結合するのと何ら変わりません (明らかに、この場合でも SQL インジェクションは可能です)。 PHP がクエリを操作するために pdo prepare で mysql_real_escape_string をローカルに呼び出すと、ローカルのシングルバイト文字セットが使用され、マルチバイトでエンコードされた変数を渡すと、依然として SQL インジェクションの脆弱性が発生する可能性があると言われています (php バージョン 5.3.6 より前の場合)この問題の 1 つは、PDO を使用する場合、php 5.3.6 以降にアップグレードし、DSN 文字列 で文字セットを指定することが推奨される理由を説明しています。

PHP 5.3.6 より前のバージョンの場合、次のコードは依然として SQL インジェクションの問題を引き起こす可能性があります:

コードをコピーします

コードは次のとおりです: $pdo->query('SET NAMES GBK');
$var = chr(0xbf) .chr(0x27) " OR 1=1 /*";
$query = "SELECT * FROM info WHERE name = ?";
$stmt = $pdo->prepare($query);
$stmt->execute(array($var));


その理由は上記の分析と一致しています。
正しいエスケープは、mysql サーバーの文字セットを指定し、変数を MySQL サーバーに送信して文字エスケープを完了することです。

それでは、PHP ローカル エスケープを無効にして、MySQL Server にエスケープさせるにはどうすればよいでしょうか?

PDO には PDO::ATTR_EMULATE_PREPARES という名前のパラメータがあり、PHP を使用してローカルでの準備をシミュレートするかどうかを示します。このパラメータのデフォルト値は不明です。先ほど確認したパケット キャプチャと分析の結果によると、PHP 5.3.6 以降は依然としてデフォルトでローカル変数を使用し、それらを SQL に結合して MySQL サーバーに送信します。この値を false に設定して効果を試してみます。次のコード内:

コードをコピーします

コードは次のとおりです: $pdo = 新しい PDO("mysql:host=192.168.0.1;dbname=test;","root");
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$st = $pdo->prepare("select * from info where id =? and name = ?");
$id = 21;
$name = '張三';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
$st->execute();
$st->fetchAll();
?>



赤い線は追加した内容です。次のプログラムを実行し、Wireshark を使用してパケットをキャプチャして分析します。結果は次のとおりです。

見ましたか?これが魔法です。今回は、PHP が SQL テンプレートと変数を 2 回に分けて MySQL に送信し、MySQL が変数のエスケープを完了することがわかります。 SQL インジェクションの問題は解決されましたが、DSN で次のように charset 属性を指定する必要があります:

コードをコピーします

コードは次のとおりです:

$pdo = 新しい PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');

このようにして、SQL インジェクションの問題を根本的に解決できます。これについてよくわからない場合は、zhangxugg@163.com に電子メールを送信して、一緒に話し合うことができます。

3. PDOを使用する際の注意点

上記の点を理解した後、PDO を使用して SQL インジェクションを防ぐためのいくつかの注意事項をまとめることができます。

1. php を 5.3.6 以降にアップグレードします。実稼働環境では、php 5.3.9 以降および php 5.4 以降にアップグレードすることを強くお勧めします。

2. php 5.3.6以降を使用している場合は、PDOのDSNにcharset属性を指定してください

3. PHP 5.3.6 以前のバージョンを使用している場合は、PDO::ATTR_EMULATE_PREPARES パラメーターを false に設定します (つまり、ローカルを使用しているかどうかにかかわらず、変数処理は MySQL によって実行されています)。シミュレーションの準備または mysql サーバーの準備を呼び出すことができます。 DSN での文字セットの指定は無効であり、セット名 の実行が必須です。

4. PHP 5.3.6 以前のバージョンを使用している場合、Yii フレームワークはデフォルトで ATTR_EMULATE_PREPARES の値を設定しないため、データベース設定ファイルで EmulatePrepare の値を false に指定してください。

そこで質問がありますが、DSN で charset が指定されている場合でも、set names を実行する必要がありますか?

はい、保存できません。 set names には実際には 2 つの関数があります:

A. クライアント (PHP プログラム) が送信したエンコーディングを mysql サーバーに伝えます

B. mysql サーバーに、クライアントが必要とする結果のエンコーディングを通知します

言い換えると、データテーブルが gbk 文字セットを使用し、PHP プログラムが UTF-8 エンコーディングを使用する場合、プログラム内でエンコーディング変換を行わずに、クエリを実行する前に set names utf8 を実行して、mysql サーバーに正しくエンコードするように指示できます。 。このようにして、クエリを utf-8 エンコーディングで mysql サーバーに送信し、取得される結果も utf-8 エンコーディングになります。これにより、プログラム内の変換エンコードの問題が解消され、文字化けしたコードが生成されることはありません。

それでは、DSN で文字セットを指定する役割は何でしょうか? これは、ローカルドライバーがエスケープするときに指定された文字セットを使用することを PDO に伝えるだけです (mysql サーバーの通信文字セットを設定するわけではありません)。 ディレクティブも使用する必要があります。

一部の新しいプロジェクトが PDO を使用せず、従来の mysql_XXX 関数ライブラリを使用する理由が本当にわかりません。 PDO を正しく使用すれば、SQL インジェクションを根本的に排除することができます。各企業の技術リーダーおよび最前線の技術研究開発担当者は、この問題に注意を払い、プロジェクトの進捗と安全性の品質を向上させるために、可能な限り PDO を使用することを強くお勧めします。 。

独自の SQL インジェクション フィルタリング関数ライブラリを作成しようとしないでください (面倒で、未知の脆弱性が簡単に作成される可能性があります)。

上記はこの記事の全内容です。非常に実践的ですので、ぜひ読んでください。

http://www.bkjia.com/PHPjc/960713.htmlwww.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/960713.html技術記事 PDO アンチインジェクションの原則と注意事項の分析 PDO が合理的かつ正しく使用されている限り、SQL インジェクションは主に次の 2 つの質問に答えます。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:PHPショートアドレス変換実装方法、PHP変換_PHPチュートリアル次の記事:PHPショートアドレス変換実装方法、PHP変換_PHPチュートリアル

関連記事

続きを見る