ホームページ >ウェブフロントエンド >htmlチュートリアル >ベスト プラクティス シリーズ (3) - PHP セキュリティの 3 つの柱: フィルタリング、検証、エスケープ - Filtering_html/css_WEB-ITnose
私たちがアプリケーションを開発するときは、一般に、自分の管理下にないデータ ソースからのデータを信頼しないという慣例があります。たとえば、次の外部ソース:
これらすべての外部ソースは、悪意のあるデータを (意図的または非意図的に) PHP スクリプトに挿入する可能性のある攻撃ベクトルとなる可能性があります。ユーザー入力を受け入れて出力をレンダリングする PHP スクリプトを作成するのは簡単ですが、安全に実行するには多大な労力が必要です。 Chen Yaojin の 3 段階の斧を導入として使用して、入力のフィルタリング、データの検証、出力のエスケープという 3 つのトリックを紹介します。
入力のフィルタリングとは、安全でない文字をエスケープまたは削除することを意味します。入力データがアプリケーションのストレージ層に到達する前に必ずフィルタリングしてください。これが防御の第一線です。 Web サイトのコメント ボックスが HTML を受け入れる場合、ユーザーは以下に示すように、悪意のある bc98f0c4d425a5fb8a5b85248570a343 タグをコメントに追加できます。ユーザーがこのページにアクセスすると、安全でない可能性のあるフィッシング Web サイトにリダイレクトされます (この攻撃には、より専門的な名前が付けられています: XSS 攻撃)。この簡単な例は、制御していない入力データをフィルタリングする必要がある理由を示す良い例です。通常、フィルタリングしたい入力データには、HTML、SQL クエリ、ユーザー情報などが含まれます。
HTML
PHP が提供する htmlentities 関数を使用して HTML をフィルタリングできます。この関数は、すべての HTML タグ文字 (&、f539a70d3ea090bac4faa80192f58ccc など) を対応する HTML エンティティに変換して取得できるようにします。アプリケーションストレージ層からの安全なレンダリング。ただし、特に画像やリンクほどではないリッチ テキストを入力する場合に、ユーザーに特定の HTML 要素の入力を許可することがあります。ただし、htmlentities は HTML を検証できず、入力文字列の文字セットを検出できないため、そのような機能は実装できません。 。
<p>这篇文章很有用!</p><script>windows.location.href=“http://laravelacademy.org”;</script>
htmlentities の最初のパラメータは処理される HTML 文字列を表し、2 番目のパラメータはエスケープされる一重引用符を表し、3 番目のパラメータは入力文字列の文字セット エンコーディングを表します。
htmlentities の反対は html_entity_decode メソッドで、すべての HTML エンティティを対応する HTML タグに変換します。
さらに、PHP には同様の組み込み関数 htmlspecialchars も提供されており、これも HTML タグの文字を HTML エンティティに変換するために使用されますが、変換できる文字は限られています (公式ドキュメントを参照してください: http://php .net/manual/ zh/function.htmlspecialchars.php)、すべての文字を変換したい場合は、引き続き htmlentities メソッドを使用します。htmlentities と同様に、htmlspecialchars にも対応するメソッド htmlspecialchars_decode があることに注意してください。
入力文字列からすべての HTML タグを直接削除したい場合は、strip_tags メソッドを使用できます。
より強力な HTML フィルタリング関数が必要な場合は、HTML Purifier ライブラリを使用できます。これは、指定されたルールを使用して HTML 入力をフィルタリングするように特別に設計された非常に堅牢で安全な PHP ライブラリです。 Laravel では、対応する拡張パッケージを使用してフィルタリング関数を実装できます: http://laravelacademy.org/post/3914.html
SQL クエリ
場合によっては、アプリケーションは入力データに基づいて SQL クエリを構築する必要があります。 HTTP リクエストのクエリ文字列は、HTTP リクエストの URI フラグメントから取得される可能性もあります。注意しないと、悪意のあるユーザーが SQL インジェクション攻撃 (SQL ステートメントを結合してデータベースを破壊したり、データを取得したりする) を実行するために使用される可能性があります。機密情報)。多くの若手プログラマは次のようなコードを作成する可能性があります:
<?php$input = '<p><script>alert('Laravel学院');</script></p>';echo htmlentities($input, ENT_QUOTES, ‘UTF-8');
これは非常に危険です。たとえば、誰かが次の方法で HTTP にリクエストを送信します:
$sql = sprintf( 'UPDATE users SET password = “%s” WHERE id = %s’, $_POST[‘password’], $_GET[‘id’]);
この HTTP リクエストは各ユーザーのパスワードを abc に設定します。これは、多くの SQL データベースが処理するためです。 - コメントの先頭として使用されるため、後続のテキストは無視されます。
SQL クエリで入力データを使用する場合は、PDO 前処理ステートメントを使用する必要があります (PDO は、さまざまなデータベース ドライバーに統合インターフェイスを提供する PHP の組み込みデータベース抽象化レイヤーです)。 )、PDO 前処理ステートメントは PDO によって提供される機能で、外部データをフィルターし、フィルターされたデータを SQL ステートメントに埋め込むことで、上記の SQL インジェクションの問題を回避できます。また、前処理ステートメントは複数のコンパイルと実行が行われます。これにより、システム リソースの占有が効果的に削減され、より高い実行効率が得られます。 PDO の後はデータベース部分に焦点を当てます。
注目に値するのは、多くの最新の PHP フレームワークは MVC アーキテクチャ パターンを使用してデータベース操作をモデル層にカプセル化しており、提供されているメソッドを使用している限り、フレームワークの最下位層はすでに SQL インジェクションをうまく回避しているということです。モデルクラスによってデータベース操作を実行する操作は、基本的に SQL インジェクションのリスクを回避できます。
Laravel を例として、基礎となる層が SQL インジェクションをどのように回避するかを見てみましょう。コードは次のようになります。
$id = $_GET['id'];$password = $_POST['password'];User::find($id)->update(['password'=>bcrypt($password)]);
由于模型类底层调用的是是查询构建器的方法,所以最终会调用Builder( Illuminate\Database\Query\Builder)的 update方法:
public function update(array $values){ $bindings = array_values(array_merge($values, $this->getBindings())); $sql = $this->grammar->compileUpdate($this, $values); return $this->connection->update($sql, $this->cleanBindings($bindings));}
这段代码传入参数是要更新的值,然后通过 $bindings获得绑定关系,这里我们我们获取到的应该是包含 password和 updated_at(默认更新时间戳)的数组,然后再通过Grammar( Illuminate\Database\Query\Grammars\Grammar)类的 compileUpdate方法生成预处理SQL语句,这里对应的sql语句是:
update `users` set `password` = ?, `updated_at` = ? where `id` = ?
然后最终将预处理sql语句和对应绑定关系传递给数据库去执行。关于SQL注入我们还会在后续数据库部分继续讨论。