その「便利さ」は諸刃の剣!Reactで安全にHTMLを扱うための防犯術
こんにちは。現場で泥臭いインシデント対応をしていると、「本当にちょっとした油断が、致命傷になるんだな」と痛感させられる場面に何度も出くわします。
今日は、React開発で時折見かける「dangerouslySetInnerHTML」という、名前からして物騒な機能についてお話しします。これ、名前の通り「危険を承知で」使う機能なんです。なぜ危険なのか、どうすれば安全に使えるのか。家の防犯に例えながら、一緒に紐解いていきましょう。
—
1. なぜ「dangerously」なんて名前なのか?
Webアプリケーションにおける「クロスサイトスクリプティング(XSS)」は、いわば「あなたの家の鍵を、泥棒が自分のスペアキーにすり替える行為」です。
通常、Reactは入力された文字を「ただの文字列」として扱います。泥棒が窓から「」という怪しい紙を投げ込んできても、Reactは「あ、これはただの文字列ですね」と無視して、画面に文字として表示するだけです。これなら安全ですよね。
しかし、dangerouslySetInnerHTMLを使うと、「投げ込まれた怪しい紙を、家の鍵穴に差し込んで実行してしまう」ことになります。つまり、ブラウザに対して「これはHTMLだから、中身をそのまま実行していいよ!」と命令してしまうのです。
XSSの3つの顔
- 反射型: 検索窓などに悪意あるリンクを仕込み、ユーザーがクリックした瞬間に被害が出る。
- 格納型: 掲示板のコメント欄などに悪意あるコードを保存させ、見た人全員を攻撃する(一番怖い!)。
- DOM型: サーバーを介さず、ブラウザ上のプログラムの隙を突いて画面を書き換える。
どれも共通しているのは、「あなたの信頼を悪用して、ブラウザに悪事を働かせる」という点です。
—
2. それでもHTMLをレンダリングしたい時は?
CMSで作成したリッチテキストを表示したり、特定の装飾が必要な場合など、どうしてもHTMLを表示せざるを得ない場面はありますよね。
そんな時は、「信頼できる掃除屋さん(サニタイザ)」を通すのが鉄則です。ここで登場するのが、セキュリティの現場でデファクトスタンダードとなっている「[DOMPurify](https://github.com/cure53/dompurify)」というライブラリです。
安全な実装例
まずは、ライブラリをインストールします。
npm install dompurify
そして、Reactのコンポーネントでは以下のように実装します。
import React from ‘react’;
import DOMPurify from ‘dompurify’; // 信頼できる掃除屋さんをインポート
const SafeHtmlComponent = ({ dirtyHtml }) => {
// DOMPurify.sanitize()が、危険なスクリプト(
コメント