説明
React で react-markdown を使用するとき、信頼できない Markdown の生 HTML を描画すると、クロスサイトスクリプティング(XSS)につながるおそれがあります。現在の react-markdown は、既定で HTML をエスケープするか無視します。rehype-raw で HTML の解析を有効にし、rehype-sanitize などでサニタイズしない場合、悪意のあるタグや属性が出力に入り込む可能性があります。旧バージョンの allowDangerousHtml や escapeHtml={false} も同じ危険を生む場合があります。
想定される影響
- 攻撃者が、ページからアクセスできる Cookie、セッション情報、その他の機密情報を取得するおそれがあります。
- ユーザーのブラウザーで悪意のあるコードが実行され、さらなる攻撃につながる可能性があります。
- 悪意のあるコンテンツによって、サイトへの信頼が損なわれる場合があります。
対処方法
- 信頼できない Markdown には
rehype-rawを使用せず、既定の描画を維持してください。 - 生 HTML が必要な場合は、
rehype-rawの後にrehype-sanitizeを適用し、許可するタグと属性のスキーマを最小限にしてください。 - ユーザーが入力した Markdown や描画するデータを検証し、サニタイズしてください。
- URL 変換オプションを変更する場合は、
javascript:、data:などの危険なスキームを拒否してください。
例
変更前
tsx
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
function UnsafeComponent({ markdown }) {
// 危険: 信頼できない Markdown の生 HTML をそのまま解析
return <ReactMarkdown rehypePlugins={[rehypeRaw]}>{markdown}</ReactMarkdown>;
}
変更後
tsx
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
function SafeComponent({ markdown }) {
// より安全な既定の動作: 生 HTML を解析しない
return <ReactMarkdown>{markdown}</ReactMarkdown>;
}
function SafeHtmlComponent({ trustedButNeedsHtml }) {
// HTML を許可する場合もサニタイズを適用
return (
<ReactMarkdown rehypePlugins={[rehypeRaw, rehypeSanitize]}>
{trustedButNeedsHtml}
</ReactMarkdown>
);
}
説明:
- 変更前:
rehype-rawだけを使用すると、Markdown 内の生 HTML が React 要素に変換されます。サニタイズされていない HTML が、コードを実行できる形で DOM に入る可能性があります。 - 変更後: 既定の描画では生 HTML を実行しません。HTML の描画が必要な場合も、
rehype-sanitizeで許可したタグと属性だけを残し、XSS の危険を減らします。