ホームページ >ウェブフロントエンド >jsチュートリアル >リッチ テキストにクロスサイト スクリプティングの脆弱性がある可能性があります
SXSS の脆弱性が悪用される前に認識して軽減します
ルーク・ハリソン著
この記事はもともと IBM Developer で公開されました。
現在のアプリケーションの多くは、Web サイト上で HTML でリッチ テキストをレンダリングする必要があります。ユーザー入力からこのフォーマットされたテキストを生成するために、開発者はリッチ テキスト エディター コンポーネントを使用します。問題?この機能により、アプリケーションとデータの両方が、ストアド クロスサイト スクリプティング (SXSS) として知られる脆弱性に間接的にさらされる可能性があります。
この記事では、SXSS 脆弱性とは何かを学び、アプリケーションが影響を受けるかどうかを確認するために使用できるいくつかの「コードの匂い」を確認します。また、脆弱なアプリケーションの例を確認し、この脆弱性の修復戦略についても学びます。
ストアド クロスサイト スクリプティングは、攻撃者がデータベースに悪意のあるコードを挿入するために悪用できる一種の脆弱性です。そのコードは、フロントエンド フレームワークによってフェッチされてレンダリングされた後、被害者のブラウザ上で実行されます。
この脆弱性は、攻撃者が Cookie を盗んだり、リダイレクトをトリガーしたり、被害者のブラウザでさまざまな危険なスクリプトを実行したりする可能性があるため、非常に危険です。エクスプロイトを広めるのに攻撃者側の作業はほとんど必要ありません。被害者は悪意のあるリンクをクリックしたり、フィッシング詐欺に引っかかったりする必要はなく、SXSS の影響を受ける信頼できるサイトを使用するだけです。クロスサイト スクリプティングの脆弱性の詳細については、ページの下部にあるリンクを確認してください。
コードの匂い は、より深刻な問題を示すコードの単なる特性です。通常、ブラウザは挿入されたスクリプトを自動的に実行しませんが、開発者が潜在的に危険なブラウザ API や要素プロパティを使用すると、スクリプトが実行されるという状況が発生する可能性があります。
次のコード スニペットを見てください:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
この例では、HTML を変数に格納し、DOM から要素を取得し、その要素の innerHTML プロパティを変数に格納されているコンテンツに設定します。 innerHTML プロパティを使用すると、別の HTML 要素内の文字列から HTML をレンダリングできます。
このプロパティの危険な点は、このプロパティに渡した HTML または JavaScript がレンダリングされることです。つまり、誰かがプロパティに渡されたデータを制御できれば、技術的にはユーザーのブラウザで任意の JavaScript を実行できることになります。
ブラウザで動的 HTML をレンダリングするもう 1 つの一般的ですが危険な方法は、dangerlySetInnerHTML React コンポーネント プロパティを使用することです。このプロパティは、バニラ JavaScript および HTML の innerHTML プロパティとまったく同じように動作します。
次の例は React ドキュメントに記載されています:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
現在フロントエンド Web アプリケーションでこれらのプロパティのいずれかを使用している場合は、何らかのクロスサイト スクリプティングの脆弱性がある可能性が高くなります。これらのプロパティが悪用される方法と、これらの問題を修復するために実行できるいくつかの手順については、この記事の後半で説明します。
アプリケーションが SXSS に対して脆弱である可能性があることを示すもう 1 つの兆候は、TinyMCE や CKEditor などのリッチ テキスト エディターを使用しているかどうかです。
ほとんどのリッチ テキスト エディターは、ユーザーが生成した書式設定されたテキストを HTML に変換することで機能します。追加のセキュリティ対策として、これらのエディタの多くは、入力から潜在的に悪意のある JavaScript を削除するために、何らかの形式のサニタイズを採用しています。ただし、リッチ テキスト コンテンツを受信して保存するサービスに同じサニタイズ手法を適用していない場合、アプリケーションが SXSS に対して脆弱になる可能性があります。
自分のサイトでコンテンツをレンダリングしていない場合でも、レンダリングを行うアプリケーションによってこのデータが消費される可能性が十分にあります。安全なアプリケーションを設計するには、データの現在および将来の消費者を考慮することが非常に重要です。データが SXSS の影響を受ける場合、データを使用するすべてのアプリケーションも影響を受けます。
SXSS の脆弱性を持つ Web アプリケーションの小さな例を見て、それを悪用してみます。
このアプリケーションを実行するには、まずこのデモ アプリ リポジトリのクローンを作成し、readme.md ファイルの「アプリケーションの実行」手順に従います。
アプリケーションを実行して http://localhost:3000/unsanitized.html に移動すると、次のようなページが表示されるはずです。
このアプリケーションは、ユーザーからリッチ テキスト入力を受け取り、それを Web サーバーに保存し、出力 というラベルの付いたセクションにレンダリングします。
SXSS の脆弱性を悪用する前に、アプリケーションを確認してください。上記のコードの匂いを参照して、コードに目を通し、問題のあるセクションを見つけられるかどうかを確認してください。ブラウザでネットワーク タブを開いて、リッチ テキストを入力して送信したときに送信されるリクエストを確認してください。
unsanitzed.html ファイルには、renderPostByID という名前の次の関数が表示されます:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
この関数をよく見てください。前述の innerHTML プロパティを使用して、API から取得したリッチ テキストを HTML 形式でレンダリングしていることがわかります。
コードの脆弱な部分が見えたので、それを悪用しましょう。リッチ テキスト エディターの入力をバイパスし、投稿を Web サーバーに直接保存する API エンドポイントにアクセスします。これを行うには、次の cURL コマンドを使用できます:
function createMarkup() { return {__html: 'First · Second'}; } function MyComponent() { return <div dangerouslySetInnerHTML={createMarkup()} />; }
リクエストで送信しているデータ ペイロードに注目してください。これは、警告ダイアログを表示する JavaScript に設定された onerror プロパティを持つイメージ タグを含む、悪意を持って作成された HTML です。攻撃者は、データベースに保存される前に HTML 要素から JavaScript を除去することを目的とした不適切に実装されたサニタイズ方法を回避するために、このようなトリックを使用します。
上記のスクリプトを実行すると、次のような投稿 ID を受け取るはずです:
const renderPostByID = async (id) => { // setting url seach params let newURL = window.location.protocol + "//" + window.location.host + window.location.pathname + `?post=${id}`; window.history.pushState({ path: newURL }, "", newURL); // getting rich text by post id let response = await fetch(`/unsanitized/${id}`, { method: "GET" }); let responseJSON = await response.json(); console.log(responseJSON); // rendering rich text output.innerHTML = responseJSON.richText; };
この投稿 ID を投稿 URL クエリ パラメーターに貼り付け、Enter を押します。
これを実行すると、サイトが実際に SXSS に対して脆弱であることを確認する警告ダイアログが画面に表示されます。
SXSS の脆弱性を悪用する方法を確認しました。次は、SXSS の脆弱性を修復する方法を見てみましょう。これを行うには、次の 3 つの異なる場所で HTML ベースのリッチ テキストをサニタイズする必要があります。
コンテンツをデータベースに保存する前と、クライアント側でレンダリングするときにコンテンツをサニタイズする理由は明らかかもしれませんが、コンテンツを取得するときにサニタイズする必要があるのはなぜでしょうか?さて、誰かがデータベースにコンテンツを直接挿入するために必要な権限を取得したと想像してみましょう。最初のサニタイザーを完全にバイパスして、悪意を持って作成された HTML を直接挿入できるようになりました。いずれかの API の利用者がクライアント側でもこのサニタイズを実装していない場合、クロスサイト スクリプティングの悪用の被害に遭う可能性があります。
ただし、3 つの場所すべてにサニタイズを追加するとパフォーマンスの低下を引き起こす可能性があるため、このレベルのセキュリティが必要かどうかを自分で判断する必要があることに注意してください。少なくとも、動的 HTML コンテンツをレンダリングする前に、クライアント側のデータをサニタイズする必要があります。
脆弱なアプリケーションの安全なバージョンにサニタイズを実装する方法を見てみましょう。このアプリケーションは主に JavaScript を使用して記述されているため、クライアント側には dompurify ライブラリを使用し、サーバー側のサニタイズには isomorphic-dompurify ライブラリを使用します。 Web サーバーとして機能する app.js プログラムには、GET および POST 実装でサニタイズされた Express エンドポイントが見つかります。
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
POST 実装では、まずリクエストの本文からリッチ テキストを取得し、それをデータ オブジェクトに保存する前に、isomorphic-dompurify ライブラリの sanitize メソッドを呼び出します。同様に、GET 実装では、データ オブジェクトからリッチ テキストを取得した後、コンシューマーに送信する前に、リッチ テキストに対して同じメソッドを呼び出します。
クライアント側では、sanitized.html の出力 div の innerHTML プロパティを設定する前に、これと同じメソッドを再度使用します。
function createMarkup() { return {__html: 'First · Second'}; } function MyComponent() { return <div dangerouslySetInnerHTML={createMarkup()} />; }
クロスサイト スクリプティングを防止するために HTML を適切にサニタイズする方法がわかったので、このアプリケーションの元のエクスプロイトに戻り、今度はサニタイズされたエンドポイントを使用してアプリケーションを再実行します。 SXSS の脆弱性を防ぐために適切な技術を使用しているため、アラート ダイアログ ポップアップは表示されなくなります。
XSS を防止するためのベスト プラクティスやその他のテクニックを含む完全な SXSS ガイドについては、OWASP クロスサイト スクリプティング チート シートをご覧ください。
この記事では、Web アプリケーションの一般的な脆弱性である保存されたクロスサイト スクリプティングを防止することで、アプリケーションのセキュリティ体制を強化する方法について説明しました。これで、自分のアプリケーションに脆弱性があるかどうか、どの機能を確認する必要があるか、悪意のある攻撃者がそれらの脆弱性を悪用する前に軽減する方法を認識できるようになります。
企業開発者にとってセキュリティは最重要です。次のリソースを使用して、潜在的な脆弱性とセキュリティ体制を改善する方法についての意識を高め続けてください。
以上がリッチ テキストにクロスサイト スクリプティングの脆弱性がある可能性がありますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。