AntiSamy による HTML/CSS のサニタイズ
ユーザーからの入力として HTML を受け取る場合には、通常その HTML に意図せぬ JavaScript などが埋め込まれないようにデータをチェックします。 これをデータのサニタイズ (sanitize) といいます。
OWASP AntiSamy を利用すると HTML/CSS をサニタイズできます。
ポリシーファイル
OWASP AntiSamy ではポリシーファイルを変更することによって、サニタイズをどのように実施するか定義できます。
事前に定義されたポリシーファイルは次の通りです。
ポリシーファイル名 | 概要 |
---|---|
antisamy-slashdot.xml | 非常に制限の厳しいポリシー。CSS は許可せず、 <b>, <u>, <i>, <a>, <blockquote> のみが許可される。 |
antisamy-ebay.xml | antisamy-slashdot.xml よりは制限の緩いポリシー。eBay 的な動作。 |
antisamy-myspace.xml | JavaScript の含まれていない HTML を許可する。 |
antisamy-anythinggoes.xml | 何でも OK |
上記ポリシーファイルをテンプレートとして、値を設定します。
利用できるオプションは次の通りです。
ディレクティブ | 型 | 既定値 | 意味 |
---|---|---|---|
useXHTML | boolean | false | XHTML フォーマットでサニタイズされたデータを出力する |
omitXMLDeclaration | boolean | true | useXHTML が true のとき AntiSamy は XML ヘッダーを付けます。 この機能を有効にすると、この動作を行いません。(つまりヘッダーを付けません) |
formatOutput | boolean | true | これを有効にすると、単純なルールによってインデントなどのフォーマットを行います。 |
maxInputSize | int | 100K | 検証前のサイズでの入力値の最大値を指定できます。 |
embedStyleSheets | boolean | false | CSS の埋め込みを許可するかどうか |
maxStyleSheetImports | int | 1 | 1 つの入力データから最大いくつの外部 CSS の取り込みを行うか指定する |
connectionTimeout | int | 1K | embedStyleSheets が有効なときの、外部 CSS リソース取り込みのタイムアウト値 |
preserveComments | boolean | false | HTML コメントを残すかどうか |
nofollowAnchors | boolean | false | これを有効にすると、全てのアンカータグに rel="nofollow" 属性が付きます。 |
validateParamAsEmbed | boolean | false | これを有効にすると、AntiSamy は embed タグの属性と、embed タグ内の param タグと同じように扱います。 ビデオなどを提供する人には必要です。 |
preserveSpace | boolean | false | これを有効化すると、空白文字をそのまま保持します |
使用方法
- *.jar ファイルとポリシーファイルダウンロードする。
AntiSamy を利用するだけなら、*.jar ファイルとポリシーファイル antisamy-*-バージョン.xml をダウンロードすれば OK です。
» AntiSamy のダウンロード - ポリシーファイルを必要に応じて変更します。
- コード例は以下を参照してください。
次の例では、テキストファイルから HTML データを読み込んで、それをサニタイズして出力しています。
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import org.owasp.validator.html.AntiSamy; import org.owasp.validator.html.CleanResults; import org.owasp.validator.html.Policy; import org.owasp.validator.html.PolicyException; import org.owasp.validator.html.ScanException; public class TestApp1 { public static void main(String[] args) throws PolicyException, ScanException, IOException { String htmlText = readFileAsString( "C:/owasp/test/test1.html"); Policy policy = Policy.getInstance( "C:/owasp/antisamy/antisamy-ebay-1.4.1.xml"); AntiSamy as = new AntiSamy(); CleanResults cr = as.scan(htmlText, policy); System.out.println(cr.getCleanHTML()); } private static String readFileAsString(String filePath) throws java.io.IOException{ StringBuffer fileData = new StringBuffer(1000); BufferedReader reader = new BufferedReader( new FileReader(filePath)); char[] buf = new char[1024]; int numRead=0; while((numRead=reader.read(buf)) != -1){ String readData = String.valueOf(buf, 0, numRead); fileData.append(readData); buf = new char[1024]; } reader.close(); return fileData.toString(); } }
ディレクティブの設定とサニタイズ後の値
antisamy-ebay-1.4.1.xml ポリシーファイルをベースとしてディレクティブを変更して、 どのように出力が変わるかみてみましょう。
変換前の HTML スニペットは次の通りです。
<script type="text/javascript"> alert('Hello, JavaScript'); </script> <style type="text/css"> h1 { color: blue; } </style> <h1>Hello, AntiSamy!</h1> <!-- Comment --> <p style="color:red;">これはテストです。</p> <p> <a href="http://www.google.com">Google</a> </p>
また、antisamy-ebay-1.4.1.xml の元のディレクティブは次のように設定されています。
<directives> <directive name="omitXmlDeclaration" value="true"/> <directive name="omitDoctypeDeclaration" value="true"/> <directive name="maxInputSize" value="20000"/> <directive name="useXHTML" value="true"/> <directive name="formatOutput" value="true"/> <directive name="embedStyleSheets" value="false"/> </directives>
既定の設定による変換
antisamy-ebay-1.4.1.xml ポリシーファイルそのままで上記 HTML を変換すると、 次のようになります。
<style type="text/css"><![CDATA[h1 { color: blue; } ]]></style> <h1>Hello, AntiSamy!</h1> <p style="color: red;">これはテストです。</p> <p> <a href="http://www.google.com">Google</a> </p>
確かに JavaScript コード、コメントが削除されていることがわかります。
ディレクティブの変更
useXHTML を false にして、さらに nofollowAnchors を追加し、値を true にしてみましょう。
<directives> <directive name="omitXmlDeclaration" value="true"/> <directive name="omitDoctypeDeclaration" value="true"/> <directive name="maxInputSize" value="20000"/> <directive name="useXHTML" value="false"/> <directive name="formatOutput" value="true"/> <directive name="embedStyleSheets" value="false"/> <directive name="nofollowAnchors" value="true"/> </directives>
変換後の結果は次の通りです。
<style type="text/css">h1 { color: blue; } </style> <h1>Hello, AntiSamy!</h1> <p style="color: red;">これはテストです。</p> <p> <a href="http://www.google.com" rel="nofollow">Google</a> </p>
デフォルトの変換結果と比べて、赤くマークした部分が正しく変わっていることがわかります。
尚、pre タグなどを許可して改行文字を認める場合以外は、次のようにして余計な改行も削除すると良いです。
String cleanHTML = cr.getCleanHTML(); cleanHTML = cleanHTML.replaceAll("(\\r|\\n)", "");