XSSを回避するためにユーザーデータを適切にエスケープする必要があるWebアプリケーションの場合、データベースに入る前に「悪いもの」を削除することをお勧めしますか、それともデータベースで許可するのが最善ですが、ページに表示されますか?
入力がデータベースに未加工で保存されているが、出力は常にエスケープされているアプリケーションがいくつかあります(少なくともこれまでのところ、私はまだ探しています!)。出力の安全性は、開発者が出力を作成するたびに文字列をエスケープすることを覚えていることに依存しているため、データベースに悪意のあるデータが表示されて不快になります...(ある種のフレームワークは、少なくともそれを収集します出力コードとフィルタリング/共通の場所へのエスケープ)
編集
明確にするために、私は既存のWebアプリケーションを監査していますが、developingではありません。 (少なくともこの質問の目的のために-私がweb開発をするとき、私はフレームワークに手を伸ばします。)私が見るものの多くは、アドホックフィルタリングおよび/または入力および/または出力でのエスケープを使用しています。 @ D.W。の答えは頭の釘を打った-私が求めていたものの本質に到達する。
すばらしい質問です。あなたは正しい質問をしています。
短い答えです。ほとんどの場合、出力側でエスケープすることが最も重要です。最善の解決策は、コンテキスト依存の自動エスケープと他のインジェクション攻撃(SQLインジェクションを回避する準備されたステートメントなど)に対する自動防御を提供するWeb開発フレームワーク(Google ctemplateなど)を使用することです。これは、入力側のサニタイズよりも効果的である可能性があります。
説明。ここには、ある入力ソース(URLパラメータなど)からの信頼できないデータのフローがあり、複雑な計算チェーン(例:データベース)、そして最終的にいくつかの出力シンク(HTMLテンプレートの動的コンテンツなど)に出力されます。消毒/エスケープはどこに置くべきですか?入力の近く、出力の近く、または中央のどこかに置くことができます。どこに配置するのが最適かをどのようにして決定しますか?それはあなたが求めていることだと思います。
パズルの最初の部分は、一貫したポリシーを持つ方が良いことを認識することです。すべてを入力に、またはすべてを出力に置く方が、入力の50%と出力の50%をサニタイズするよりも適切です(後者を行うと、ポリシーが遵守されていることを確認するのが難しくなります。一貫性があり、信頼できないソースから出力シンクへのデータの流れになり、サニタイズ/エスケープされることはありません)。 「データベース内のすべてがすでにサニタイズおよびエスケープされ、すべて信頼できるものとして扱うことができる」または「データベース内の何もサニタイズまたはエスケープせず、すべて信頼できないものとして扱う必要がある」というポリシーを持つことをお勧めします(または文書化されたポリシーを持たないよりも、データベース内のどのフィールドがすでにサニタイズ/エスケープされていると信頼できるか、どのフィールドが信頼できるかを文書化するポリシーを持つこと。
パズルの2番目の部分は、次のことを質問することです。サニタイズ/エスケープを正しく行うために、知っておくべき追加情報はありますか?信頼できない入力がどこから来たかについての情報を知る必要がありますか?それが使用される場所(出力のどの部分に挿入されるか)に関する情報を知る必要がありますか?
ほとんどの場合、答えは次のとおりです。信頼されていないデータが使用される場所(HTML出力に表示される場所)を知る必要がありますが、どこから来たのかを知る必要はありません。 HTML文書のどこに挿入するかを知る必要があります。これにより、エスケープ機能の選択が決まります。タグの間に挿入する場合は、HTMLエスケープを使用して<
、>
をエスケープする必要があります。 、および&
;属性内に挿入する場合は、引用符もエスケープする必要があります。 URLとして挿入する場合は、プロトコルスキームも確認する必要があります(javascript:
URLではないことを確認するため)。この情報は、出力シンクではすぐに利用できますが、入力ソースでは利用できません。出力側でエスケープを実行する場合、この情報はすぐに利用できます。動的データをHTMLドキュメントに挿入すると、挿入される解析コンテキストについて必要なすべての情報が手元にあります。一方、入力ソースをサニタイズしようとすると、データがどこで使用される可能性があるかが明確でないため、どのようにエスケープする必要があるかを知ることは困難です。したがって、これは入力ソースでサニタイズするのではなく、出力シンクでエスケープすることを示唆しています。
パズルの3番目のピースは、 context-sensitive auto-escaping を実行するWebプログラミングフレームワークがあることです。通常、テンプレートシステムを使用し、テンプレートに動的に挿入される値ごとに、挿入先のHTMLコンテキストを調べます(タグ内か、属性内か、URL値か、JavaScript内か)。 、使用する必要のあるエスケープ関数を見つけ、そのエスケープ関数を自動的に適用します。適切なエスケープ関数が確実に使用され、値をエスケープするのを忘れた場合の脆弱性を排除するため、これは大きな勝利です。今日、これらの種類の脆弱性は両方とも一般的です: 開発者はしばしばいくつかの値をエスケープすることを忘れ、エスケープすることを覚えていると、しばしば値が使用されるコンテキストに間違ったエスケープ関数を適用します 。状況依存の自動エスケープにより、これらの脆弱性は本質的に排除されます。
ディスカッション。つまり、最善の防御策は、出力での状況依存エスケープと入力検証の両方を使用することです入力時の/ sanitization。状況に応じて、最も重要な防御ラインを回避することを検討します。ただし、(有効なデータがどのように見えるかについての期待に基づいて)入力で値をサニタイズすることも、多層防御の形式として良い考えです。ある種のプログラミングエラーを排除または軽減し、それらの悪用を困難または不可能にすることができます。
既存のフレームワークを使用して、入力の検証と出力のエスケープを行うことを強くお勧めします。
入力のエスケープには3つの大きな問題があります。
より重要:入力時のエスケープは、出力時よりも入力時の方が簡単なので、ほとんど効果がありません。また、両方を実行してもデータが破壊されるため、明らかに機能しません。
エスケープを念頭に置いておくという負担からドメイン開発者を解放するフレームワーク(JSFなど)を使用する必要があります。これにより、表示コンポーネントの技術的な部分のコードが非常に少なくなり、適切なエスケープを完全に認識する必要があります。バグの可能性を大幅に削減し、監査と教育を簡素化するため、少量の重要なコードが適しています。
あなたはいつもそれを置く場所に影響を与える「悪いもの」を除外します。
したがって、データベースにデータを送信している場合は、データベースインジェクションを回避できます。 HTMLに送信する場合は、HTMLインジェクションを回避します。これは、エスケープが2回行われることを意味しますが、別のものです。
これは単なる好みの問題ではありません。代わりに、これはあなたのアプリケーションstaysが将来的に安全であることを保証します。たとえば、データベースに挿入されたデータをHTMLエスケープする場合、悪意のあるユーザーがHTMLをDBに取り込む方法を見つけた場合、データベースはスクリプトやその他のHTMLベースの攻撃の潜在的な媒介となります。
言い換えれば、エクスプロイトのポイントにできるだけ近づくようにエスケープすることで、全体的な攻撃面を減らします。
理想的には3つすべてです。ある時点で、入力画面で作業している開発者がチェックを省くと仮定します(または、チェックを破る新しいエクスプロイトが発生する可能性が高い)。入力での検証の難しさは、新しいエクスプロイトが発生した場合、検証を修正する前に悪意のあるデータをすでに受け入れている可能性があることです。ある時点で、出力に取り組んでいる開発者がフィルタリングを除外する(または、新しいエクスプロイトがフィルターを壊す)と想定します。
したがって、可能であれば、入力、出力、およびデータベース制約として検証を行ってください。制約が変更されるたびに、既存のすべてのデータが新しいルールに対して再検証されます。
いずれかを選択する必要がある場合、新規および既存のデータに拡張が適用されるため、それが出力になります。
うまくいけば、「入力はデータベースにそのまま保存される」と言ったときは、SQLインジェクション攻撃から保護するためにすでにサニタイズされています。
私見、あなたがすでにその仕事をしているなら、あなたもXSSのいたずらを取り除くためにあなたができる最善を尽くすかもしれません。
入力フィルタリングの方法と配置は、実際には処理されたデータの特定の状況と要件によって異なりますが、以下の4つの原則を考慮して検討します。
1)できるだけ厳密で厳密なフィルタリングと検証を使用する
2)複数の冗長な防御レベルを使用する
3)データのサニタイズが、データが使用されるコンテキストに適していることを確認してください!!
4)フレームワークまたは他の自動化を使用している場合、それが何をしているか、およびそのEdgeケースを理解する
最初の原則の適用、およびデータベースでフィルタリングされていないデータを許可するかどうかに関する質問への回答は、多くの場合、アプリケーションの機能要件によって異なります。たとえば、HTMLタグが含まれてはならない姓または名を収集する場合は、タグを処理する最も早い時点でタグを取り除くことができます。年齢フィールドまたは価格フィールドがある場合は、値を数値にしてから、他の操作を行うことができます。
ただし、タグやスクリプトスニペットを含む可能性があるこのサイトへのユーザー投稿など、任意のユーザーデータを操作する必要がある場合があり、場合によっては元のデータにアクセスする必要があります。次に、いくつかのアプローチが可能です。安全でないデータを保存し、表示する前にそれをフィルタリング/エンコードします。消毒したバージョンを保存し、必要に応じて元のバージョンに変換します。そして最後に、それを必要とするアプリケーションの元のデータ(「レッドストリーム」)と、表示目的で使用されるサニタイズバージョン(「グリーンストリーム」)の両方を格納します。
データベース内のデータが適切にサニタイズされているという強力な保証がない限り、DBを外部ソースと見なし、そこからのデータに入力フィルタリングを適用することは価値があります。データフローのいくつかのポイント(初期入力処理、データベースデータ、および場合によっては出力エンコーディング)で入力検証を実行すると、XSS&Coに対して複数の防御策が提供されます。
入力/出力のサニタイズの適切な方法を選択する際の重要な問題は、データがページ上のどこに、どのHTMLコンテキストで表示されるかを知ることです。データが「通常の」位置(いわゆるHTMLコンテキスト)に移動する場合、通常、htmlタグの除去またはhtmlentityエンコードで十分ですが、タグのhref属性の値として挿入しようとすると不十分です。タグが入力から取り除かれると、ここをクリックして「ワンクリックXSS」の脆弱性が発生する可能性があります。 https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet のルールを注意深く検討してください
最後に、フレームワークまたはサニタイズライブラリに関する注意事項-これらは非常に効果的であるため、正確に危険な場合があります。通常、これらは「通常の」/より簡単なケースの95%で素晴らしく機能し、特別なコンテキスト(属性、Javascriptなど)のサニタイズなど、Edgeケースに適切なことを行うのを忘れる可能性があります。