やめる!
あなたはここで間違いを犯しています。ああ、いいえ、あなたはあなたのデータを少し安全にするために適切なPHP関数を選びました。それはいいです。間違いは、操作の順序と、これらの関数をどこでどのように使用するかです。
ユーザーデータのサニタイズと検証、ストレージへのデータのエスケープ、およびプレゼンテーションへのデータのエスケープの違いを理解することが重要です。
ユーザーデータの無害化と検証
ユーザーがデータを送信するときは、期待どおりのものが提供されていることを確認する必要があります。
サニタイズとフィルタリング
たとえば、数値が予想される場合は、送信するデータが数値である ことを確認してください。ユーザーデータを他のタイプにキャストすることもできます。送信されたものはすべて最初は文字列のように扱われるため、既知の数値データを整数または浮動小数点数に強制すると、サニタイズが迅速かつ簡単になります。
自由形式のテキストフィールドとテキストエリアはどうですか?これらのフィールドに予期しないものが何もないことを確認する必要があります。主に、HTMLコンテンツがないはずのフィールドに実際にHTMLが含まれていないことを確認する必要があります。この問題に対処する方法は2つあります。
まず、でHTML入力のエスケープを試すことができますhtmlspecialchars
。htmlentities
HTMLの無効化には使用しないでください。HTMLは、エンコードする必要があると思われるアクセント付き文字やその他の文字のエンコードも実行するためです。
次に、可能なHTMLをすべて削除してみます。 strip_tags
迅速かつ簡単ですが、ずさんなこともします。 HTML Purifierは、すべてのHTMLを取り除き、タグと属性の選択的なホワイトリストを通過させるという、より徹底的な作業を行います。
最新のPHPバージョンにはフィルター拡張機能が同梱されており、ユーザー入力をサニタイズするための包括的な方法を提供します。
検証
送信されたデータに予期しないコンテンツが含まれていないことを確認することは、仕事の半分にすぎません。また、送信したデータに実際に使用できる値が含まれていることを確認する必要もあります。
1から10までの数値が予想される場合は、その値を確認する必要があります。スピナーとステップでこれらの新しい派手なHTML5時代の数値入力の1つを使用している場合は、送信されたデータがステップと一致していることを確認してください。
そのデータがドロップダウンメニューである必要がある場合は、送信した値がメニューに表示されたものであることを確認してください。
他のニーズを満たすテキスト入力についてはどうですか?たとえば、日付の入力は、strtotime
またはDateTimeクラスを介して検証する必要があります。指定された日付は、予想される範囲内である必要があります。メールアドレスはどうですか?前述のフィルター拡張機能は、アドレスが整形式であることを確認できますが、私はis_emailライブラリーのファンです。
他のすべてのフォームコントロールについても同様です。ラジオボタンがありますか?リストに対して検証します。チェックボックスがありますか?リストに対して検証します。ファイルをアップロードしましたか?ファイルが予期したタイプであることを確認し、ファイル名をフィルタリングされていないユーザーデータのように扱います。
すべての最新のブラウザーには、開発者ツールの完全なセットが組み込まれているため、誰でも簡単にフォームを操作できます。 コードでは、ユーザーがフォームコンテンツのクライアント側の制限をすべて完全に削除したと想定する必要があります。
ストレージのためのデータのエスケープ
データが期待される形式であり、期待される値のみが含まれていることを確認したので、そのデータをストレージに永続化することについて心配する必要があります。
すべてのデータストレージメカニズムには、データが適切にエスケープおよびエンコードされるようにする特定の方法があります。SQLを構築している場合、クエリでデータを渡す方法として受け入れられているのは、プレースホルダー付きの準備済みステートメントを使用する方法です。
PHPでほとんどのSQLデータベースを操作するためのより良い方法の1つは、PDO拡張機能です。それは共通のパターンは以下の声明を準備し、ステートメントに変数をバインド、その後、サーバーへの文と変数を送信します。これまでにPDOを使用したことがない場合は、MySQL指向の非常に優れたチュートリアルがあります。
SQL ServerやPostgreSQL、SQLite 3など、一部のSQLデータベースにはPHPで独自の拡張機能があります。これらの各拡張機能には、PDOと同じprepare-bind-execute方式で動作するステートメントサポートが用意されています。非標準の機能や動作をサポートするために、PDOの代わりにこれらの拡張機能を使用する必要がある場合があります。
MySQLには、独自のPHP拡張機能もあります。そのうちの2つ。mysqliと呼ばれるものだけを使用したいだけです。古い「mysql」拡張機能は廃止されており、現在の時代に使用するのは安全または正気ではありません。
私は個人的にはmysqliのファンではありません。準備されたステートメントで変数バインディングを実行する方法は柔軟性がなく、使いにくい場合があります。疑わしい場合は、代わりにPDOを使用してください。
SQLデータベースを使用してデータを保存していない場合は、使用しているデータベースインターフェイスのドキュメントを確認して、データを安全に渡す方法を確認してください。
可能な場合は、データベースにデータが適切な形式で格納されていることを確認してください。数値フィールドに数値を格納します。日付フィールドに日付を格納します。浮動小数点フィールドではなく、10進数フィールドにお金を格納します。さまざまなデータ型を適切に格納する方法について、データベースが提供するドキュメントを確認してください。
プレゼンテーション用のデータのエスケープ
ユーザーにデータを表示するときは常に、エスケープしてはいけないことがわかっていない限り、データが安全にエスケープされていることを確認する必要があります。
HTMLを出力するときは、ほとんどの場合、最初にからユーザーが提供したデータを渡す必要がありますhtmlspecialchars
。実際には、あなたはときにこれを行うべきではないだけの時間がある知っているユーザーがHTMLを提供することを、あなたがいることを知って、それはすでにホワイトリストを使用して消毒されていますということ。
PHPを使用してJavascriptを生成する必要がある場合があります。JavaScriptには、HTMLと同じエスケープルールはありません。PHPを介してJavascriptにユーザー指定の値を提供する安全な方法は、を使用することjson_encode
です。
もっと
データ検証にはさらに多くのニュアンスがあります。
たとえば、文字セットのエンコーディングは巨大な罠になる可能性があります。アプリケーションは、「UTF-8まで」に概説されているプラクティスに従う必要があります。文字列データを誤った文字セットとして扱う場合に発生する可能性のある架空の攻撃があります。
以前、ブラウザーのデバッグツールについて説明しました。これらのツールは、Cookieデータの操作にも使用できます。 クッキーは信頼できないユーザー入力として扱われるべきです。
データの検証とエスケープは、Webアプリケーションのセキュリティの1つの側面にすぎません。Webアプリケーションへの防御を構築できるように、Webアプリケーションの攻撃方法を自覚する必要があります。