web-dev-qa-db-ja.com

PHPサイトでxss攻撃を回避するためのベストプラクティスは何ですか?

私はPHPが構成されているので、マジッククオートがオンになり、レジスタグローバルがオフになります。

ユーザー入力から派生した、出力しているものすべてに対して常にhtmlentities()を呼び出すように最善を尽くします。

私は時々、添付されたxssで使用される一般的なものについてデータベースを検索します...

<script

他に何をすべきか、そして私がやろうとしていることを常に確実に行うにはどうすればよいですか?.

65
Rik Heywood

入力のエスケープは、XSS防止を成功させるためにできる最善の方法ではありません。また、出力はエスケープする必要があります。 Smartyテンプレートエンジンを使用する場合は、|escape:'htmlall'修飾子を使用してすべての機密文字をHTMLエンティティに変換できます(私は上記のエイリアスである独自の|e修飾子を使用しています)。

入出力セキュリティへの私のアプローチは:

  • 変更されていないユーザー入力の保存(入力でのHTMLエスケープなし、PDO準備済みステートメントを介したDB対応のエスケープのみ)
  • 使用する出力形式に応じて、出力時にエスケープします(例:HTMLとJSONには異なるエスケープルールが必要です)
58

私は、出力時にのみ、入力中には何もエスケープしてはならないという意見です。 (ほとんどの場合)そのデータがどこに向かっているのかを知っているとは想定できません。たとえば、後で送信するメールに表示されるデータを取るフォームがある場合は、別のエスケープが必要です(そうしないと、悪意のあるユーザーがメールヘッダーを書き換えることができます)。

言い換えると、データがアプリケーションから「離れる」最後の瞬間にのみエスケープすることができます。

  • リストアイテム
  • XMLファイルに書き込み、XMLにエスケープする
  • DBへの書き込み、エスケープ(特定のDBMSの場合)
  • メールを書き、メールを逃れる

短くするには:

  1. データの行き先がわからない
  2. データは実際には複数の場所に配置される可能性があり、異なるエスケープメカニズムが必要ですが、両方は必要ありません
  3. 間違ったターゲットのためにエスケープされたデータは、本当に素晴らしいものではありません。 (たとえば、「トミーのバーに行く」という件名のメールを受け取ります。)

Esp#3は、入力レイヤーでデータをエスケープした場合(または、再度デエスケープする必要がある場合など)に発生します。

PS:次に、magic_quotesを使用しないことについてのアドバイスを紹介します。これらは純粋に悪です。

18
Jilles

XSSを行う方法はたくさんあり( http://ha.ckers.org/xss.html を参照)、キャッチするのが非常に困難です。

私はこれを、現在使用している現在のフレームワーク(たとえば、コードイグナイター)に個人的に委任します。完璧ではありませんが、私の手作りのルーチンがこれまで以上にキャッチするかもしれません。

12

これは素晴らしい質問です。

まず、入力時にテキストをエスケープしないでください(データベースに格納するなど)を安全に保管するためです。この理由は、入力した内容を保持して、状況に応じてさまざまな方法や場所で表示できるようにするためです。ここで変更を加えると、後のプレゼンテーションが損なわれる可能性があります。

あなたがデータフィルターを提示するとき、そこにあるべきでないものを除外します。たとえば、JavaScriptが存在する理由がない場合、それを検索して削除します。これを行う簡単な方法は、 strip_tags 関数を使用して、許可するHTMLタグのみを提示することです。

次に、持っているものを取り、htmlentitiesまたはhtmlspecialcharsを渡して、そこにあるものをASCII文字に変更します。これは、コンテキストと取得したい内容に基づいて行います。

また、Magic Quotesをオフにすることをお勧めします。これはPHP 6から削除されており、使用することは悪い習慣と見なされています。詳細は http://us3.php.net/magic_quotes

詳細については、チェックアウト http://ha.ckers.org/xss.html

これは完全な答えではありませんが、うまくいけば、あなたが始めるのに役立つのに十分です。

10
Matt Farina

ユーザー入力から派生した、出力しているものすべてに対して常にhtmlentities()を呼び出すように最善を尽くします。

.

See Joel's essay on Making Code Look Wrong for help with this

7
Mason

私は [〜#〜] phptal [〜#〜] に依存しています。

SmartyやプレーンPHPとは異なり、デフォルトではすべての出力をエスケープします。 htmlspecialchars()または|escapeをどこかで忘れてもサイトが脆弱になることはないため、これはセキュリティにとって大きなメリットです。

XSSはHTML固有の攻撃であるため、HTML出力はそれを防ぐための適切な場所です。 HTMLを受け入れないが、独自のリスクがある別のメディアにデータを出力する必要がある可能性があるため、データベース内のデータを事前にフィルタリングしないでください。

4
Kornel

テンプレートライブラリ。または、少なくとも、それはテンプレートライブラリがすべきことです。 XSSall出力を防止するには、出力をエンコードする必要があります。これはメインアプリケーション/制御ロジックのタスクではなく、出力メソッドによってのみ処理されます。

コード全体にhtmlentities()を振りかけると、全体的なデザインが間違っています。そして、あなたが提案するように、あなたは1つか2つのスポットを見逃すかもしれません。これが、厳密なhtmlエンコーディング-> when出力変数がhtml/xmlストリームに書き込まれる唯一の解決策である理由です。

残念ながら、ほとんどのphpテンプレートライブラリは独自のテンプレート構文を追加するだけですが、出力のエンコーディング、ローカリゼーション、またはhtml検証など、重要なことには関係ありません。多分誰かがphpの適切なテンプレートライブラリを知っていますか?

4
user319490

XSS攻撃が心配な場合は、出力文字列をHTMLにエンコードすることが解決策です。すべての出力文字をHTML形式にエンコードすることを覚えている場合、XSS攻撃を成功させる方法はありません。

続きを読む: ユーザーデータのサニタイズ:方法と場所

2
Niyaz

個人的には、magic_quotesを無効にします。 PHP5 +では、デフォルトで無効になっています。すべてをエスケープせず、PHP6から削除されるため、まったく存在しないかのようにコーディングすることをお勧めします。

次に、フィルタリングしているユーザーデータのタイプに応じて、次に何をするかが決まります。それが単なるテキストの場合、例えば名前、次にstrip_tags(trim(stripslashes())); itまたは範囲を確認するには正規表現を使用します。

特定の範囲の値が予想される場合は、有効な値の配列を作成し、それらの値は(in_array($userData, array(...)))のみを許可します。

数値をチェックする場合は、is_numericを使用して整数を適用するか、特定のタイプにキャストすると、代わりに文字列を送信しようとするのを防ぐことができます。

PHP5.2 +を使用している場合は、 filter() を確認し、電子メールアドレスを含むさまざまなデータタイプをフィルタリングできる拡張機能を利用することを検討してください。ドキュメントは特に良いわけではありませんが、改善されています。

HTMLを処理する必要がある場合は、 PHP入力フィルター または HTML Purifier のようなものを検討する必要があります。 HTML Purifierは、HTMLの適合性も検証します。入力フィルターがまだ開発中かどうかはわかりません。どちらでも、使用できるタグのセットと許可する属性を定義できます。

あなたが決めることは何であれ、常に覚えておいてください。PHPユーザーからのスクリプト(自分を含む!).

2
Dave

この関数を使用すると、考えられる多くのxss攻撃を取り除くのに役立ちます。 http://www.codebelay.com/killxss.phps

2
barce

「マジッククオート」は、入力時にすべてをエスケープすることによって機能する、最悪のXSS欠陥のいくつかに対する一時的な救済策であり、設計上は間違っています。 XSSに関して不注意に書かれていることが知られている既存のPHPアプリケーションが絶対に使用する必要がある場合です(この場合、あなたは深刻な問題に直面しています) 「マジッククオート」を使用した場合でも)。独自のアプリケーションを開発する場合は、「マジッククオート」を無効にし、代わりにXSSセーフプラクティスに従う必要があります。

クロスサイトスクリプティングの脆弱性であるXSSは、アプリケーションが外部ソースからの文字列(ユーザー入力、他のWebサイトから取得したものなど)を[X] HTML、CSS、ECMAscript、または適切にエスケープせずに期待する他のブラウザー解析出力に含む場合に発生します小なり([X] HTML)、一重引用符または二重引用符(ECMAscript)などの特殊文字は表示されません。これに対する適切な解決策は、出力言語の規則に従って常に文字列をエスケープすることです。[X] HTMLでのエンティティの使用、ECMAscriptでのバックスラッシュなど。

信頼できないものやエスケープする必要があるものを追跡するのは難しいため、HTMLなどの言語の「マークアップ付きのテキスト」ではなく、常に「テキスト文字列」であるすべてのものをエスケープすることをお勧めします。一部のプログラミング環境では、「文字列」(通常のテキスト)、「HTML文字列」(HTMLマークアップ)など、互換性のないいくつかの文字列タイプを導入することで、より簡単になります。この方法では、「文字列」から「HTML文字列」への直接の暗黙的な変換は不可能であり、文字列がHTMLマークアップになる唯一の方法は、それをエスケープ関数に渡すことです。

「グローバルの登録」は、無効にすることは間違いなく良いことですが、XSSとはまったく異なる問題を扱います。

2

ほとんどのサイトでは、すべてのユーザー入力をエスケープするだけで十分です。また、セッションIDがURLに含まれないようにして、Refererリンクから別のサイトに盗まれないようにしてください。また、ユーザーにリンクの送信を許可する場合は、javascript:プロトコルリンクが許可されています。これらは、ユーザーがリンクをクリックするとすぐにスクリプトを実行します。

2
Konrad Rudolph

これらの答えはすべて素晴らしいですが、基本的に、XSSの解決策は、文字列操作によるHTMLドキュメントの生成を停止することです。

入力のフィルタリングは、どのようなアプリケーションにとっても常に良いアイデアです。

Htmlentities()およびフレンドを使用して出力をエスケープすることは、それが適切に使用されている限り機能するはずですが、これはmysql_real_escape_string($ var)で文字列を連結してSQLクエリを作成することと同等のHTMLです。 、いわば、パラメーター化されたクエリを使用するようなアプローチと比較して。

長期的な解決策は、おそらくDOMのような標準インターフェースを使用してページを内部的に構築し、次にライブラリ(libxmlなど)を使用してXHTML/HTMLなどへのシリアル化を処理することです。もちろん、人気があり、十分に高速であることから遠く離れていますが、当面は文字列操作を介してHTMLドキュメントを構築する必要があり、それは本質的にリスクが高くなります。

2
Daniel Papasian
  • ユーザー入力を信頼しない
  • すべてのフリーテキスト出力をエスケープします
  • Magic_quotesは使用しないでください。 DBMS固有のバリアントがあるかどうかを確認するか、PDOを使用します
  • 悪意のあるスクリプトがセッションを乗っ取ることができないように、可能な場合はHTTPのみのCookieの使用を検討してください
1
Rob

少なくとも、データベースに入るすべてのデータを検証する必要があります。そして、データベースを離れるすべてのデータを検証してみてください。

mysql_real_escape_stringはSQLインジェクションを防ぐのに適していますが、XSSは扱いにくいです。可能であれば、preg_match、stip_tags、またはhtmlentitiesを使用してください。

1
Abeon

PHPアプリケーションでXSSを防止するための現在の最良の方法は、HTML Purifier(http://htmlpurifier.org/)です。これの小さな欠点の1つは、かなり大きなライブラリであり、最もよく使用されることです。 APCのようなopコードキャッシュを使用します。これは、信頼できないコンテンツが画面に出力されている任意の場所で使用します。htmlentities、htmlspecialchars、filter_input、filter_var、strip_tagsなどを使用するほうがはるかに簡単です。

1
Night Owl

HttpOnlyを使用するセッションCookie(またはすべてのCookie)を作成します。その場合、ほとんどのブラウザーはJavaScriptからCookie値を隠します。ユーザーは引き続きCookieを手動でコピーできますが、これによりスクリプトへの直接アクセスを防止できます。 StackOverflowには、ベータ版でこの問題がありました。

これは解決策ではなく、壁にある別のレンガです

1
basszero

最善の方法は、コードをバインドできるクラスを使用することです。手動でデータをエスケープすることを心配する必要はありません。

0
Darren22

既存のユーザー入力サニタイズライブラリを使用してクリーンアップallユーザー入力。 lotの労力を費やさない限り、自分で実装してもうまくいきません。

0
dbr