web-dev-qa-db-ja.com

JSON経由のXSS:Webアプリケーションがスクリプトのような悪意のあるタグの着信paramsハッシュまたは発信JSON値のいずれもサニタイズしないのはなぜですか?

最近、会社のRailsベースのWebアプリケーションに取り組んでいたため、XSSの脆弱性を調査する必要がありました。一部の場所では、アプリケーションがHTMLタグを使用できることがわかりました(例:<script>jscodehere</script> GETまたはPOSTリクエストのパラメータとして直接。

このパラメーターには、アプリケーションのparamsハッシュ(すべての着信キー/値データがリクエストから利用可能になるハッシュ)を介してアクセスできます。

現在、XSSの脆弱性は、サイトがそのバージョンの多くのページのデータをJSONバージョン(/cart/1.json)。

私が完全に理解していないいくつかのメカニズム(これは技術的に「Reflected XSS」だと思いますか?)によって、無害化されていない<script>その後JSONに組み込まれたコードは、意図しない実行により、個人のマシンや他のサイトを危険にさらすために使用できます。

私の質問は、なぜこれがオプトインシステムではないのですか? Railsはバージョン4になりました。そのため、ソリューションを手動でビルドする必要があることに驚いていますが、これはすべてのWebアプリケーションフレームワークに適用されます。パラメーターを無害化しないようにすることの1つです。デフォルトでは(おそらく、ユーザーのプロファイルページでHTMLタグが使用され、フォーマットが必要になる可能性があります)–そして、Railsは、実際のレンダリングアクションでもいくつかのスクラブを行い、出力を制限します。デフォルトでは、「安全な」htmlタグのみ。

しかし、JSONをレンダリングする場合、おそらくJSONのサニタイズ/スクラブは行われません。おそらく、JSON応答が構築および解析されるときに、あまりにもカスタマイズされているためですが、その理由は完全には理解できません。

1)一部の組み込みメカニズムが適切ではありません

2)これについてはこれ以上触れていません。RailsまたはWeb上のSinatraアプリからのJSONレンダリングでのHTML/Scriptタグの安全でない受け渡しについての説明は見つかりませんでした( paramsハッシュのサニタイズに関する少量の情報なので、INの途中で値をサニタイズします。これは間違いなく優れていますが、万能ソリューションであり、HTMLを保持する必要がある場合があります。タグは取り除きますが、<script>タグなど)。

3)Rubyの世界では、少なくとも現在のところ、サニタイズ用に存在するライブラリは1つしかありません(サニタイズGem、それは実際には文字列データ型でのみ機能します。書き込む必要があります) paramsハッシュのように、ハッシュをサニタイズするための独自の再帰的コードであり、これにも何も書かれていないようです!)Railsには組み込みのサニタイザーがありますが、このサードパーティのサニタイズジェムよりも劣っており、サニタイズの深さ(文字列)にいくつかのレベルの厳密性を持たせることに関しては、それほど柔軟ではありません。

JSONへのインジェクションの有効性を脆弱性と誤解していますか、またはJSONがすべてのWebアプリケーションのコア機能ではないため、この脆弱性は見過ごされていますか?

最終結果:バックエンドのメインアプリケーションコントローラーでbefore-filterを使用して、リクエストから来るたびに、Sanitizeライブラリを使用してparamsハッシュをサニタイズしました。

ただし、これはすべてのリクエストで発生する必要があるため、アプリケーションの速度が大幅に低下し、サニタイザーは基本的にハッシュに対して再帰的な方法で一連の正規表現呼び出しを実行していると思います。この方法では、タグがデータベースに入力されることはなく、JSONを介してタグを作成することもできませんが、パフォーマンスの面でコストがかかります。もっと良い方法はありますか?

11
rcd

これは多くの場合、あらゆる場所で発生します。これは、入力された衛生が答えであるというマントラを繰り返し皆が繰り返し続けているためです。そうではありません。危険でバグが発生しやすく、立ち去る必要があります。もちろん、入力の長さが適切な列に正しく対応しているかどうかを常に確認する必要があります。

入力のサニタイズと出力のサニタイズ。


入力を無害化すると、それを回避する方法が非常に多くなり、適切に実装することが困難になるため、人々に誤った安心感が与えられ、開発者はgoogleで安全でない古い実装を検索する必要があります。このため、outputをサニタイズすることをお勧めします。

これが後で行われる理由の1つは、正しいデータを保持するだけでなく、SQLインジェクション攻撃から保護するためです。 SQLインジェクション攻撃は、実際には入力の衛生ではなく、準備されたステートメントによって大部分が打ち負かされます。すべてのスクリプトタグと危険な出力を htmlエンティティ に置き換える必要があります。

次に、入力ではなく出力で、潜在的なスクリプト文字をhtmlエンティティに置き換える例を示します。

  1. <&lt;になりますが、ページでは<として表示されますが、レイアウトやデータベースを変更する必要はありません。

  2. >&gt;になりますが、ページでは>として表示されますが、レイアウトやデータベースを変更する必要はありません。


では、なぜ入力をサニタイズしないのですか?それを正しく実装するとどうなりますか?

ほとんどの開発者はITセキュリティの専門家ではありません。ほとんどの開発者は、この領域で何をすべきか手掛かりがありません。これらの2つの一般的なデータ保護方法を教えることで、開発時間を節約し、Webアプリケーションの全体的なセキュリティを大幅に向上させることができます。さらに、開発者が2340939403424の異なるタイプの入力サニテーションが必要な理由ではなく、なぜこれが必要なのかを理解し、後で必ず発生する多くの実装の問題を防ぐことができます。

前に言ったように、古い入力衛生機能をgoogleで検索することはセキュリティではありません。それは誤った安心感です。許容できるものと許容できないもの、およびデータが通過するプロセスを理解する必要があります。

出力の衛生管理を使用すると、後で忘れていた奇妙なバグが発生することを心配する必要はありません。誤って実装される可能性のある多数の複雑な機能をいじくり回したり、誤った安心感を与える必要はありません。スクリプトが挿入されることを心配する必要もありません。

しかし、挿入前にすべてのHTMLエンティティを置き換えるとどうなるでしょうか。クライアント側でこれを試すと、誰でもリクエストを変更できる可能性があります。それらをデータベースに入れる前にバックエンドでチェックすると、それもうまくいくかもしれません...しかし、問題があります

実際のHTMLエンティティを配置する必要があるフィールドがある場合はどうなりますか?パッケージング、アドレス、またはそのような愚かなものとしましょう。多分それはファイル名かもしれませんし、多分それはあなたが何らかの方法で実装したものかもしれません。


入力衛生が吸う理由の例

たぶん、誰かが自分の名前や住所に別のアポストロフィを使用する面白いキーボードを持っているでしょうか?これにより、一部のデータベースがユニコードベースの密輸に開放されたままになる可能性があります。

多分あなたはその中に< or >を持っているレコードが必要ですか?何をする? HTMLエンティティで検索しますか?これはかなり非効率的であり、多くのデータベースで正しく機能させるには多くのハックが必要です。

たぶん誰かの名前にアポストロフィが含まれているかもしれません-たとえば、Rory O'Cune。入力サニテーションを使用すると、彼の名前を破棄し、それを処理するためにより多くのコードが必要になります。従業員の1人が姓で検索していて、OCuneに短縮されているために彼を見つけることができない場合はどうなりますか?これはひどいです。

これが、入力されたサニテーションではなく、パラメーター化されたクエリを使用するもう1つの理由です。準備されたステートメントと出力の衛生を使用して、これを行うことができます:

SELECT * FROM [table] WHERE [last_name] = @Lastname -- (or ?)

@Lastname(Javaでは?になります)パラメータ/バインドされた変数はO'Cuneに正しく変換されます。面白いビジネスは必要ありません。追い詰めるバグはありません。無限に安全であり、改ページ文字であればhtml entityを出力できます。


では、なぜRubyこれを自動的に修正しないのですか?

なぜ彼らは?これらのスクリプトタグを自動的に削除するany言語でのJSONの実装はまだ見つかっていません。 JSONを使用して、Webサイトになんらかの理由でスクリプトタグを表示したい場合はどうでしょうか。

この機能を削除することで、JSONを介してHTMLを出力することを防止できます。

したがって、答えはそれを行うことですyourself。これらのスクリプトタグをシリアル化して返す前に、Htmlエンティティに置き換えます。

10
Mark Buffalo

入力を安全にすることは、できるだけ遅くする方が良いでしょう。つまり、データがページに出力されるときです。この段階では良いデータと悪いデータを区別することが不可能であるため、入力データをグローバルに「サニタイズ」することは悪いことです(つまり、ユーザーがHTMLの入力を許可している場合、フレームワークは違いを区別できません)存在するはずのHTMLと存在しないHTMLの違い)。スクリプトが入力されている場合でも、これは有効な場合があります(コードを含むStackOverflow/StackExchangeテキストボックスを考えてください)。

その後、できるだけ遅く、アプリケーションは、出力の形式に応じてエンコードする必要があります。たとえば、HTMLやJSONなどです。前者と&の記号は&amp;になり、表示用に適切にレンダリングされます。後者の場合、JSONエンコーダーを使用して&\x26に変換する必要があります。 JSON文字列。

スクリプトはJSONリクエストからブラウザで実行されないため、JSON自体はXSSリスクではありません(JSONPは、データとしてロードされるのではなく、スクリプトsrc参照に含まれているため、別の問題です)。 JSONでのXSSリスクは、ページ上のJavaScriptが、取得したJSONデータでHTML要素を作成または入力しようとする場合です。 JavaScript自体は、データをHTMLエンコードするか、安全なオブジェクトメンバーを使用してDOMに入力する必要があります(例 textContent )。

サニタイズは追加のレイヤーとして実行できますが、適切なエンコーディングに焦点を合わせる必要があります。たとえば、郵便番号または郵便番号に英数字とスペース文字のみが含まれていることをサーバー側で検証したい場合があります。より複雑なフィールドの場合、これは、入力機能を大幅に制限しない限り選択できません。

request validation を使用した.NETなど、一部のフレームワークはデータをグローバルにサニタイズしようとします。しかし、脆弱性は常に これはごく最近のもの を含めて見つかります。要するに、それは機能せず、それを試みる言語の機能上の問題を引き起こします。また、アプリケーション自体以外のソースから取得されたデータのXSSからの保護も提供しません。

8
SilverlightFox