Slide 1

Slide 1 text

ReactのdangerouslySetInnerHTMLは “dangerously”だから危険 dangerouslySetInnerHTMLから学ぶinnerHTML系XSSの発生原因とその対策 Security.any #09 卒業したいセキュリティLT プロフェッショナルサービス部 石川琉聖 @ryusei_ishika

Slide 2

Slide 2 text

自己紹介 Ryusei Ishikawa id: xryuseix / twitter: @ryusei_ishika GMO Flatt Security(株) プロフェッショナルサービス部 脆弱性診断やセキュリティAIエージェントを提供する会社です Webの脆弱性診断やペネトレーションテストをしています 好きな脆弱性はXSS・RCE © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 3

Slide 3 text

皆さんに質問 Q. Slackの検索機能のような、ユーザーが検索した文字列の一部を ハイライトしたい時、Reactでどう実装しますか? Slackで「卒業」と検索した結果 A. ??? © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 4

Slide 4 text

皆さんに質問 Q. Slackの検索機能のような、ユーザーが検索した文字列の一部を ハイライトしたい時、Reactでどう実装しますか? Slackで「卒業」と検索した結果 ↑正規表現でマッチしたものをタグで囲う。結果をHTMLとして表示。 © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 5

Slide 5 text

皆さんに質問 Q. Slackの検索機能のような、ユーザーが検索した文字列の一部を ハイライトしたい時、Reactでどう実装しますか? Slackで「卒業」と検索した結果 ↑正規表現でマッチしたものをタグで囲う。結果をHTMLとして表示。 本当にこれでいい? © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 6

Slide 6 text

ReactのdangerouslySetInnerHTMLって? 特定のDOM要素にHTMLを追加する属性 (Webにおける Element.innerHTML プロパティの React での代替) → このコードは... こうなる https://developer.mozilla.org/ja/docs/Web/API/Element/innerHTML https://ja.legacy.reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 7

Slide 7 text

dangerouslySetInnerHTMLはいつ使いたくなるの? テキストの装飾系 「**これは太字**」と書かれた文字列を 「これは太字」に
 変換して表示するとき Markdownエディタ ユーザーが入力した文字列を
 ハイライトで表示する Slackの検索機能 HTMLビルダー系 独自サイトのノーコードで作れる系 HTMLやCSSを用いてページの
 デザインをカスタマイズできる系 © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 8

Slide 8 text

dangerouslySetInnerHTMLを使ったらどうなる? XSS 悪意あるJSを他ユーザの
 ブラウザ上で実行する攻撃 されること: アカウント乗っ取り 意図しない不正操作 勝手な投稿や決済など ページ情報の漏洩 ユーザ情報が書かれてい るページなど ... (ブラウザ上でできること がなんでもされる) CSSインジェクション
 (CSSi) 悪意あるCSSを他ユーザの
 ブラウザ上で表示する攻撃 されること: 画面の改ざん 操作の妨害 入力内容の漏洩 パスワードが
 抜き取られるかも © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 9

Slide 9 text

XSSって実世界のプロダクトでどれくらい発生しているの? Flattでは今でも4番目に多い脆弱性となっている https://blog.flatt.tech/entry/flatt_top10_2025 © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 10

Slide 10 text

dangerouslySetInnerHTML以外に似た危険な機能って他に何がある? JavaScript Element.innerHTML = "hoge" jQuery $('div').html('

hoge

'); Python - Django {% autoescape off %} A. いっぱいある PHP - Twig {{ hoge|raw }} Vue.js

© 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 11

Slide 11 text

でもこう実装すれば安全じゃないの? 安全そうな実装.js という文字が含まれていたらダメという実装 ※ 正確には、dangrouslySetInnerHTMLはscriptタグが実行されません。
 ここでは分かりやすさのために、あえてこのような書き方にしています。 © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 12

Slide 12 text

でもこう実装すれば安全じゃないの? 安全そうな実装.js という文字が含まれていたらダメという実装 攻撃可能なスクリプト <scriptの後ろにスペースを入れればいい © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 13

Slide 13 text

でもこう実装すれば安全じゃないの? 安全そうな実装_v2.js scriptという文字(山括弧は除く)が含まれていたらダメという実装 © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 14

Slide 14 text

でもこう実装すれば安全じゃないの? 安全そうな実装_v2.js scriptという文字(山括弧は除く)が含まれていたらダメという実装 攻撃可能なスクリプト 大文字小文字を含めたsCrIpTとかにすればいい © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 15

Slide 15 text

でもこう実装すれば安全じゃないの? 安全そうな実装_v2_改.js ユーザーからの文字を小文字にした結果、scriptという文字が含まれていたらダメ © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 16

Slide 16 text

でもこう実装すれば安全じゃないの? 安全そうな実装_v2_改.js ユーザーからの文字を小文字にした結果、scriptという文字が含まれていたらダメ 攻撃可能なスクリプト XSSとして攻撃可能なタグはscriptだけではない。onhoge=属性が攻撃に便利! © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 17

Slide 17 text

でもこう実装すれば安全じゃないの? 安全そうな実装_v2_改_最終版.js onhoge=という文字が含まれていたらダメという実装 © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 18

Slide 18 text

でもこう実装すれば安全じゃないの? 安全そうな実装_v2_改_最終版.js onhoge=という文字が含まれていたらダメという実装 攻撃可能なスクリプト onhoge=を禁止してもダメ、色んなテクがある © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 19

Slide 19 text

でもこう実装すれば安全じゃないの? Q. 対策、無理じゃね...? A. はい、激ムズです... ←謎のスラッシュ ←svgonloadタグ?そして何語? ←謎のタグ、謎属性 ↑全てが謎 人類には意味不明なテクニックが、世の中には沢山あります... (シンタックスハイライトが壊れちゃった...) © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 20

Slide 20 text

じゃあどう対策すれば? 対策方法1: Reactのエスケープ機能を使用する ❌️ 脆弱な実装 ⭕️ 安全な実装 でも複雑なプログラムでの変換はとても大変...という人は次のスライドへ © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 21

Slide 21 text

じゃあどう対策すれば? 対策方法2: DOMPurifyを使う ⭕️ 安全な実装 DOMPurifyとは、HTML内のJavaScriptとして実行される部分だけを削除するOSS Cure53というドイツのセキュリティ企業が中心となって開発 Cure53 - GitHub - cure53/DOMPurify: DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. https://github.com/cure53/DOMPurify © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 22

Slide 22 text

じゃあどう対策すれば? 軽減策 (根本的な対策 ではなく、保険みたいなやつ) HttpOnly Cookie やること: 認証関連のCookieに HttpOnly 属性を付与す る でも: セッションキーは盗めないけど 、悪意のあ る操作をされ る Content-Security-Policy (CSP) やること: こんな感じのヘッダーを返す Content-Security-Policy: default-src 'none'; script-src 'nonce-{ランダムな値}'; style-src 'self'; img-src 'self'; でも: CSPの設定ミスでよく迂回される & サイトの表示が壊れる可能性有 ドメインの分離 やること: 管理者画面など は別のドメインでホストされ るよう にす る でも: 同一ドメイン内なら攻撃可能 & 認証認可が複雑に sandbox属性付きiframe やること: XSSあ るかもコンテンツを iframe に閉じ 込める、可能なら sandbox 属性を付与 でも: 複雑な条件で、刺さる時は刺さる © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 23

Slide 23 text

皆さんに明日・週明け会社でやってほしいこと dangerouslySetInnerHTMLやv-htmlなどを文字列検索してください “リファクタリングの一環”だと思って、別のスッキリした実装ができないか考えてみてください 調査・修正はLLMにお願いするのもOK Claude CodeならClaude Code Securityや/security-reviewコマンドなどを使うと楽かも © 2025 GMO Flatt Security Inc. All Rights Reserved.

Slide 24

Slide 24 text

まとめ 意外とXSSはよく見つかるし、見つかった時の深刻度は高い innerHTML系の機能は使いたくなるシーンが多い 自力で対策は難しい、ライブラリの機能を使って対策して 今日ここで、XSSから“卒業”しよう © 2025 GMO Flatt Security Inc. All Rights Reserved.