ユーザー入力は「毒入り」だと思え!DOMPurifyで安全なHTMLを手に入れる方法
こんにちは。現場でセキュリティの最前線に立っているエンジニアです。
皆さんは「ユーザーが自由に書き込める掲示板」や「プロフィール編集画面」を作るとき、どんな気持ちでコードを書いていますか?「まあ、適当にタグを入れられても表示されるだけだし大丈夫でしょ」なんて思っていたら、それは「家のドアを全開にして、誰でも自由に入ってきていいよ」と言っているのと同じなんです。
今回は、Web開発で避けては通れない「HTMLインジェクション(クロスサイトスクリプティング:XSS)」という泥棒から身を守るための、最も現実的で強力な武器「DOMPurify」について、一緒に紐解いていきましょう。
—
なぜ「HTML」をそのまま表示してはいけないのか?
まず、攻撃者が何を狙っているのかを想像してみましょう。
皆さんのWebサイトに、もしこんな文字列が投稿されたらどうなるでしょうか。
ブラウザは律儀にこれを読み込みます。「画像がないぞ? じゃあエラーが発生したから、alertという命令を実行しよう!」と動いてしまうのです。これが、悪意あるスクリプトが実行される仕組みです。
これを防ぐための「家の防犯」には、大きく分けて2つのアプローチがあります。
1. ブラックリスト方式(NG集を作る): 「はダメ」「onerrorはダメ」と禁止事項を並べる方法。しかし、攻撃者はあの手この手で「タグの中に隠す」などの裏をかいてきます。これではイタチごっこになり、結局防ぎきれません。
2. ホワイトリスト方式(OKなものだけ入れる): 「許可リストにあるタグだけ通す」。これが今回紹介する「無害化(サニタイズ)」の基本理念です。
---
DOMPurify:最強の「門番」を雇う
「じゃあ、自分でホワイトリストを作らなきゃいけないの?」と不安になる必要はありません。世界中のエンジニアが信頼しているDOMPurifyというライブラリを使えば、強力な門番を簡単に雇うことができます。
DOMPurifyは、入力されたHTMLを一度バラバラに分解し、「安全なタグ(や
など)」と「安全な属性」だけを選別して、それ以外を問答無用でゴミ箱に捨てるという処理をしてくれます。
導入のステップ
まずはパッケージをインストールしましょう。
npm install dompurify TypeScriptを使っているなら型定義も忘れずに npm install @types/dompurify --save-dev
実践コード:こうやって使う!
フロントエンドで安全に表示させるためのシンプルなコード例です。
import DOMPurify from 'dompurify';
// ユーザーから送られてきた「危険なHTML」 const dirtyInput = '
こんにちは!
';
// DOMPurifyに「無害化」をお願いする
// これだけで危険なタグや属性はすべて削除されます
const cleanHTML = DOMPurify.sanitize(dirtyInput);
// 結果を表示する(安全!)
// 出力結果:
こんにちは!
document.getElementById('content').innerHTML = cleanHTML;
見ての通り、onerrorやは影も形もなくなっていますよね。これが「無害化」の威力です。
---
さらにセキュリティを強固にする:CSP(コンテンツ・セキュリティ・ポリシー)
DOMPurifyで「中身」を綺麗にしたら、次は「外側」の防御も固めましょう。ここで登場するのがCSP(Content Security Policy)というHTTPヘッダーです。
これは「ブラウザに対する、サイトの行動制限ルール」です。
例えば、Webサーバーからブラウザにこう伝えます。
Content-Security-Policy: default-src 'self'; script-src 'self';
これは、「このサイトで動かしていいスクリプトは、自分のサーバーにあるものだけだよ。外部から読み込ませたり、インラインで直接書いたりするのは禁止!」という強い命令です。
たとえDOMPurifyをすり抜けるような未知の脆弱性が見つかったとしても、CSPという「二重の鍵」があれば、攻撃者はスクリプトを実行できず、被害を最小限に抑えることができます。
---
最後に:セキュリティは「完璧」を目指さない
セキュリティの世界では、「100%安全なシステム」は存在しません。しかし、「攻撃するコストを最大化する」ことは可能です。
1. DOMPurifyで入力の無害化を行う(ホワイトリスト方式)
2. CSPヘッダーで実行環境を制限する
3. 常にライブラリを最新に保つ
この3つを徹底するだけで、あなたのサイトは「格好の標的」から「割に合わない堅牢な要塞」へと変わります。
最初は難しく感じるかもしれませんが、まずは「ユーザーからの入力をそのまま信じない」という意識を持つこと、それが何よりの第一歩です。一歩ずつ、泥臭く、着実に実装していきましょう。何か困ったことがあれば、いつでもまた聞きに来てくださいね!
コメント