Knowledge Center
技術情報などを公開しています
en ja zh
XSS対策の実践

セキュアなWeb開発のためのDOMPurify入門

By Author
image
Webアプリケーションの普及に伴い、クロスサイトスクリプティング(XSS)攻撃は深刻なセキュリティリスクとして認識されています。XSSは、悪意のあるスクリプトがユーザーのブラウザで実行される脆弱性を悪用する攻撃手法です。 本記事では、JavaScriptライブラリであるDOMPurifyを用いてXSS攻撃を効果的に防止する方法を、ハンズオン形式で解説します。プログラミングの基礎知識を持つ読者を対象に、実践的なコード例を通じて、セキュアなWeb開発の手法を学びます。

XSS攻撃の概要とそのリスク

XSS攻撃は、ユーザー入力が適切に「サニタイズ (*1)」されずにWebページへ埋め込まれることで発生します。たとえば、コメント欄に入力されたスクリプトがそのままHTMLとしてレンダリングされる場合、攻撃者は任意のJavaScriptを実行できます。

これにより、セッションの乗っ取り、個人情報の窃取、偽装コンテンツの表示などが可能となります。
DOMPurifyは、このような入力データを安全に処理するための強力なツールであり、信頼性の高いサニタイズ機能を提供します。

(*1) サニタイズとはユーザーからの入力データに含まれる危険な要素(=悪意あるコードや意図しない制御文字列)を無害化、または除去する処理を指します。

DOMPurifyの基本とセットアップ

DOMPurifyは、HTML、SVG、MathMLのコンテンツをサニタイズし、危険なスクリプトや属性を除去するライブラリです。軽量で設定も容易なため、モダンなWebアプリケーションに適しています。

まず、DOMPurifyをプロジェクトに導入する方法を説明します。以下は、CDNを利用してDOMPurifyをHTMLファイルに組み込む例です。

<!DOCTYPE html>    
<html lang="ja">    
<head>    
    <meta charset="UTF-8">    
    <title>XSS対策ハンズオン</title>    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.1.6/purify.min.js"></script>    
</head>    
<body>    
    <h1>DOMPurifyデモ</h1>    
    <textarea id="input" rows="5" cols="50"></textarea>    
    <button onclick="sanitizeInput()">サニタイズ</button>    
    <div id="output"></div>    
    <script>    
        function sanitizeInput() {    
            const input = document.getElementById('input').value;    
            const clean = DOMPurify.sanitize(input);    
            document.getElementById('output').innerHTML = clean;    
        }    
    </script>    
</body>    
</html>    

このコードをブラウザで実行し、テキストエリアに <script>alert('XSS');</script> と入力して「サニタイズ」ボタンをクリックしてください。
DOMPurifyによりスクリプトタグが除去され、安全なテキストのみが出力されます。

ハンズオン:ユーザー入力のサニタイズ

実際にDOMPurifyを使ったサニタイズのプロセスを体験しましょう。以下のシナリオを想定します。

あるWebアプリケーションで、ユーザーのコメント投稿を可能とする。コメントにはHTMLタグを部分的に許可したいが、スクリプトや危険な属性は除去したい。

DOMPurifyの設定をカスタマイズして、特定のタグのみを許可する例を示します。

<!DOCTYPE html>    
<html lang="ja">    
<head>    
    <meta charset="UTF-8">    
    <title>カスタムサニタイズデモ</title>    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.1.6/purify.min.js"></script>    
</head>    
<body>    
    <h1>カスタムサニタイズ</h1>    
    <textarea id="input" rows="5" cols="50"></textarea>    
    <button onclick="sanitizeCustom()">サニタイズ</button>    
    <div id="output"></div>    
    <script>    
        function sanitizeCustom() {    
            const input = document.getElementById('input').value;    
            const clean = DOMPurify.sanitize(input, {    
                ALLOWED_TAGS: ['p', 'strong', 'em'],    
                ALLOWED_ATTR: ['style']    
            });    
            document.getElementById('output').innerHTML = clean;    
        }    
    </script>    
</body>    
</html>    

このコードでは、ALLOWED_TAGS<p>, <strong>, <em> を許可し、ALLOWED_ATTRstyle 属性を許可しています。
<script>onerror などの危険な要素は自動的に除去されます。

たとえば:

DOMPurifyの高度な設定とベストプラクティス

DOMPurifyは柔軟にカスタマイズ可能です。たとえば:

などの設定が可能です。

また、セキュリティ関連ライブラリは脆弱性対応のため頻繁に更新されるため、定期的な更新が重要です。

以下のベストプラクティスを推奨します:

  1. 常に最新バージョンのDOMPurifyを使用する
  2. 許可するタグ・属性は必要最小限に限定する
  3. サニタイズ後の出力も、サーバー側で検証する

これらにより、多層防御を実現し、さらに安全性を高めることができます。

実際のアプリケーションでの応用

DOMPurifyは、ブログのコメント欄、チャットアプリ、CMSのコンテンツ入力など、ユーザー生成コンテンツを扱う多様な場面で活用可能です。

たとえば、ReactアプリケーションでDOMPurifyを使用する場合、以下のように実装できます。

import React, { useState } from 'react';    
import DOMPurify from 'dompurify';    
    
const App = () => {    
    const [input, setInput] = useState('');    
    const [output, setOutput] = useState('');    
    
    const handleSanitize = () => {    
        const clean = DOMPurify.sanitize(input, {    
            ALLOWED_TAGS: ['p', 'strong', 'em'],    
            ALLOWED_ATTR: ['style']    
        });    
        setOutput(clean);    
    };    
    
    return (    
        <div className="p-4">    
            <h1 className="text-2xl font-bold">ReactでのXSS対策</h1>    
            <textarea    
                className="w-full p-2 border"    
                rows="5"    
                value={input}    
                onChange={(e) => setInput(e.target.value)}    
            ></textarea>    
            <button    
                className="mt-2 p-2 bg-blue-500 text-white"    
                onClick={handleSanitize}    
            >    
                サニタイズ    
            </button>    
            <div    
                className="mt-4 p-2 border"    
                dangerouslySetInnerHTML={{ __html: output }}    
            ></div>    
        </div>    
    );    
};    
    
export default App;    

このReactコンポーネントは、ユーザー入力をサニタイズして安全にレンダリングします。
dangerouslySetInnerHTML を使用する際は、必ずDOMPurifyなどのサニタイズ処理を行うことが重要です。

まとめ

DOMPurifyは、XSS攻撃を防ぐための強力かつ柔軟なツールです。

本記事では:

をハンズオン形式で解説しました。

セキュアなWeb開発においては、適切なサニタイズとライブラリの更新が不可欠です。
DOMPurifyを活用することで、ユーザー生成コンテンツを安全に取り扱い、信頼性の高いアプリケーションを構築できます。

おすすめの記事