Webメールでは、受信したHTMLメールのタグを残して、クライアントサイドスクリプト(JavaScriptなど)のみを除去するサニタイズ処理を行ないます。
このようなスクリプト除去処理は、Blog、掲示板などでも行なわれる、比較的ポピュラーなものであるため、それ用のライブラリがいくつか存在します*1。
HTML Purifierもその一つです。PHP4/5で動作します。バージョン1.0.0のリリースは2006年9月ですから、比較的新しいものです。私は昨年末に初めて触ってみました(バージョン1.3.2です)。
これまでのものと比べて、非常によく出来ているなと思いましたので、日記に書いてみます。
HTML Purifierの概要
特徴としては、以下が挙げられると思います。
HTMLを再構築
(当然ですが)HTMLをParseして分解する⇒フィルタ適用⇒HTML再構築という手順で処理します。
HTML言語仕様知識を持つ
HTMLやCSS言語仕様がライブラリに収められており、言語仕様に基づくフィルタ処理を行ないます。これがこのライブラリの最大の売りです。
- タグの包含関係をチェック。
- 属性値を分類し(bgcolor属性は%Color、width属性は%Length、src属性は%URIなど)、分類毎のチェックパターンで属性値をチェック。
- style属性値もホワイトリストでチェック。
HTML Purifierに関するより詳細な情報は、以下のページで得られます。
HTML Purifier - Filter your HTML the standards-compliant way!
処理の流れ
もう少しだけ詳細に、HTML Purifierの処理の流れを追っていきます。
前処理
Parse処理
- PHP4では独自Parser、PHP5ではDOM関数を使う。
- 開始・終了タグ、空タグ(空要素)、Textに分解する。
- Text、属性値内のBig5文字参照を展開する。
フィルタリング
- 許可するタグ以外(コメント含む)を削除。
- 終了タグの追加などで、整形式(Well-formed)にする。
- 包含関係が不正なタグを削除。
- 許可する属性以外を削除。
- 属性タイプに応じて属性値をチェック。不正な属性は削除。
HTML生成
- 開始・終了タグ、空タグ、TextをHTMLに展開する。
- Text、属性値内の< > " &を文字参照化する。
ベースとなる言語仕様
このライブラリで使用できるタグ、属性、CSSプロパティは、HTML Purifier Printer Smoketestに記述されています。基本的に、HTML4.01(Transitional)、CSS Level 1をベースにしているように思われます。
しかし、言語仕様で定義されていながら、このライブラリでは使用できないものもあります(SCRIPTタグやイベント系属性だけではありません)。例えば、以下です。
- IFRAME、STYLE、OBJECT/APPLET、AREA、FORMタグ関連
- テーブル類の背景色・幅指定属性
- Aタグのtabindexやaccesskeyなどの属性
- 背景画像指定のCSSプロパティ
このライブラリはページの一部分に、外部のHTMLを挿入するような使い方を前提としています。そのような使い方にそぐわないタグ、属性などを使用不可にしているという理由もあるようです。
また、一部の属性値やCSSプロパティ値に、必要以上に厳しい制限を掛けています。例えば、CSSで「MS明朝」のようなマルチバイト文字を含むフォント名は指定できません(/* foo */ 形式でのコメントなども使用できません)。
利点と欠点
既存ライブラリと比較しての、利点と欠点です。
欠点:HTML記述の制約が多い
本質的な問題ですが、このライブラリは言語仕様準拠でないHTMLを許容しません(違反している要素を無視するだけで、HTML全体を拒絶するわけではありません)。世の中の多くのHTMLは、言語仕様に準拠しているとは思えませんので、何らかの影響が出ます。さらに、実際に適用されるフィルタは、言語仕様より厳しい基準のものです。
欠点:サーバリソースを消費する
既存のライブラリと比べて処理は複雑です。測定していませんが、消費するCPU、メモリ資源は相対的に多いと考えられます。処理時間も掛かるでしょう。
感想
CSSにさえもホワイトリストを適用しているのは驚きです。欠点もありますが、進んだ発想のライブラリだと思います。少なくとも、既存のPHPのスクリプト除去用ライブラリや、巷のポータルサイトのWebメールのフィルタよりも、はるかに良いです。
通常のページと、外部由来のHTMLを表示するページを分離する対策(ドメインや認証用トークンなどを分離し、XSS被害が波及しないようにする)が難しい場合には、使用を検討する価値があると思います。
*1:PHPのライブラリは、拙文「よりセキュアなWebサイト構築 - 4.7 JavaScriptの除去」にまとめています。HTML_Safe、kses、HTML Filter for PHPなどを試しましたが、いずれも安全とはいえないものでした。
*2:ライブラリへの入出力時にコード変換を行います。ライブラリの内部処理はUTF-8です。他の文字コードを使う場合、コード変換ロジックによっては、スクリプト挿入の危険性があるので要注意です(参考:UNICODE とサニタイジング回避テクニック)。コード変換にはiconvが使用されます。