沖縄チームのキリです。ウェブサービスでHTMLを入力したいという要望、よくありますよね?リッチテキストエディタを導入して簡単にHTMLを入力し、またそれをそのまま表示させることはそう難しくありません。ですが、セキュリティ脆弱性の懸念があります。<script>を埋め込むことでXSS(クロスサイトスクリプティング)攻撃を実行できたり、<iframe>で外部サイトを埋め込んだり、閉じタグを入れてサイトのレイアウトを崩したり…HTMLタグを許可することはそれなりの危険を伴います。不特定多数が入力フォームを利用できる場合は尚更いうまでもありませんね。
今回はそういうケースで役立つHTML Purifierというライブラリを紹介します。Purifierという単語を調べると清浄器と出てきます。HTML PurifierはHTMLテキストをパースし、ホワイトリスト方式で許可したもの以外のHTMLタグやstyle属性等を除去することが可能です。
https://github.com/ezyang/htmlpurifier
以前に運用していたウェブサイトにて導入したことがありましたが、当時HTML5や新しいCSSにあまり対応しておらず、一部機能を拡張して使用していましたが、リリースノートを見ると今でも更新は続いており、PHP8.4にも対応していたため改めて調べ記事にしたいと思いました。
https://github.com/ezyang/htmlpurifier/releases
ただしこの記事を書いている時点で4.18.0が最新版なのに対しドキュメントのダウンロードリンクが4.15.0のままだったりと、ドキュメントの更新がリリースに追いついていないことには多少不安がありますね…(未だにSSL化していないところも…)
ドキュメントを軽く確認したところ、対応しているDoctypeはHTML 4.01 Transitional / StrictおよびXHTML 1.0 Transitional / Strict、XHTML 1.1のみで、相変わらずHTML5で追加された要素には対応していないようでした、残念…。
さて、使い方ですが、ドキュメントを見てもよく分かりません。使ったのは昔のことですっかり忘れてしまったのでChatGPTで次のように聞いてみました。(composerを使わないやり方だったので、composerを使用した例に書き直してもらいました)
HTML Purifier
https://github.com/ezyang/htmlpurifier
このライブライブを使用して安全ないくつかのHTMLタグとCSSスタイルを許可し、入力されたHTMLを無害化するサンプルプログラムを記述してください
<?php
// Composerのautoloadファイルを読み込む
require_once 'vendor/autoload.php';
// 入力されたHTML (例としてユーザー入力を想定)
$input_html = '<div style="color: red; font-size: 16px;">安全なHTMLテキスト</div><script>alert("XSS!");</script>';
// HTML Purifierの設定を作成
$config = HTMLPurifier_Config::createDefault();
// 許可するHTMLタグを指定
$config->set('HTML.Allowed', 'div,span,b,strong,i,em');
// 許可するCSSプロパティを指定
$config->set('CSS.AllowedProperties', ['color', 'font-size', 'text-align']);
// 無害化処理で不要なCSSやタグを削除するためのオプション
$config->set('AutoFormat.RemoveEmpty', true);
// HTML Purifierインスタンスを作成
$purifier = new HTMLPurifier($config);
// HTMLを無害化
$clean_html = $purifier->purify($input_html);
// 結果を表示
echo "無害化されたHTML:\n";
echo htmlspecialchars($clean_html);
念の為コンフィグについてのドキュメントを確認しましたが、問題なさそうです。ChatGPT、スゴイ!
http://htmlpurifier.org/live/configdoc/plain.html
このコードでは出力時にhtmlspecialchars
を通しており、HTML Purifierを使用せずともXSS攻撃が成立することはありませんが、HTMLを表示したいので実際にはこのようなエスケープ処理をせずに出力することになります。この例では<script>alert("XSS!");</script>
の部分がきれいに取り除かれ、入力されたHTMLを安全に出力することができます。
今回はHTML Purifierを紹介させていただきましたが、いかんせん古いライブラリなだけに、新しいHTMLやCSSに対応しておらず、クラス名がPSR-0のままになっているのは使用に躊躇いますね…他に新しくこのようなHTMLを無害化するライブラリがあれば是非紹介して欲しいところです。