1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】ReactでのXSS脆弱性コードとその対策

Posted at

はじめに

こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。

SPA 開発でよく話題になるセキュリティリスクのひとつが XSS(クロスサイトスクリプティング) です。
React はデフォルトでユーザー入力をエスケープしてくれるので一見安心ですが、油断すると簡単に XSS が入り込みます。

この記事では、React でやりがちな XSS 脆弱性のあるコード例と、その回避方法をまとめます。


XSS とは

よく聞くXSSですがそこまで複雑に考える必要はありません。
XSS とは HTML に<script>などのようなJavaScript をいれることで認証情報(トークン、Cookie)の窃取などを行われてしまいます。

React が安全な理由と危険なパターン

  • {value} として描画 → React が自動でエスケープしてくれるので安全
  • dangerouslySetInnerHTMLinnerHTML 直書き → エスケープされないので危険

つまり、React のエスケープ機構をバイパスした瞬間に危険になります。


ありがちな脆弱コード例と修正版

1. dangerouslySetInnerHTML にユーザー入力を突っ込む

NG

<div dangerouslySetInnerHTML={{ __html: userComment }} />

OK

import DOMPurify from "dompurify";

<div
  dangerouslySetInnerHTML={{
    __html: DOMPurify.sanitize(userComment),
  }}
/>

2. DOM操作で innerHTML に代入

NG

useEffect(() => {
  ref.current!.innerHTML = userInput; // 危険
}, [userInput]);

OK

import DOMPurify from "dompurify";
useEffect(() => {
  ref.current!.innerHTML = DOMPurify.sanitize(userInput);
}, [userInput]);

3. ユーザー入力を href/src に直入れ

NG

<a href={userProvidedUrl}>リンク</a>

OK

const url = new URL(userProvidedUrl, window.location.origin);
const safe = ["http:", "https:"].includes(url.protocol) ? url.toString() : "#";

<a href={safe}>リンク</a>

4. MarkdownをそのままHTML化

NG

import { marked } from "marked";
<div dangerouslySetInnerHTML={{ __html: marked(userMarkdown) }} />

OK

import DOMPurify from "dompurify";
import { marked } from "marked";

const html = DOMPurify.sanitize(marked.parse(userMarkdown));
<div dangerouslySetInnerHTML={{ __html: html }} />

script だけじゃない!注意すべき攻撃パターン

XSS といえば <script>alert(1)</script> を思い浮かべる人が多いですが、実際はもっと多様です。

  • <img src=x onerror=alert(1)>
  • <a href="javascript:alert(1)">
  • <svg onload=alert(1)>

つまり タグや属性を丸ごと削除(サニタイズ)しないと防げないんです。


実戦での対策まとめ

  • ユーザー入力は基本 JSX {value} で描画(自動エスケープに任せる)
  • HTML を描画する必要があるなら DOMPurify などでサニタイズ
  • URL は new URL() でパースし、許可スキームのみ使用
  • サーバ側で CSP (Content Security Policy) を設定し、防御を二重化

まとめ

React だからといって XSS に無敵なわけではありません。
「ユーザー入力をそのまま HTML として扱わない」
この原則を徹底するだけでも、大部分の XSS は防げます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?