最近仕事でもプライベートでもPHPしか書いてないので、久々にPHPネタを。
HTMLを入力できるフォームを作りたくって、ただscriptタグやonloadなど、スクリプトを実行する要素が入ってほしくなかったので、そのバリデーションを書いた。
ただ正規表現として処理するだけだと不十分だと思ったので、DOM的に解析して、scriptタグやonから始まる属性があれば不正なHTMLとして処理することにした。
続きにサンプルコードを書く。
<?php /* // 正常パターン $html = <<<DOC <p style="color:red">test1<a href="#">hoge</a></p> <p>test2<a href="#">hoge</a></p> DOC; */ /* // HTMLが不正パターン $html = <<<DOC p style="color:red">test1<a href="#">hoge</a></p> <p>test2<a href="#">hoge</a></p> DOC; */ /* // empty $html = ''; */ /* // onclick 埋められたパターン $html = <<<DOC <p style="color:red">test1<a href="#" onclick="alert(1);">hoge</a></p> <p>test2<a href="#">hoge</a></p> DOC; */ // <script> 埋められたパターン $html = <<<DOC <p style="color:red">test1<a href="#">hoge</a></p> <p>test2<a href="#">hoge</a></p> <script>alert(1);</script> DOC; function validateNode($node) { foreach ($node->attributes() as $name => $attr) { if ((strlen($name)) > 1 && (strtolower(substr($name, 0, 2)) == 'on')) { return false; } } foreach ($node->children() as $child) { $name = $child->getName(); if (strtolower($name) == 'script') { return false; } if (!validateNode($child)) { return false; } } return true; } function validateHtml($html) { if (empty($html)) { return true; } $domDocument = new DOMDocument(); $domDocument->loadHTML($html); $xmlString = $domDocument->saveXML(); $xmlObject = simplexml_load_string($xmlString); return validateNode($xmlObject->body); } if (validateHtml($html)) { echo "HTML is secure."; } else { echo "HTML is insecure!"; }
CakePHP 3 のバリデーターとしたものを gist に貼っておいた。
[PHP] 入力されたHTMLにscriptタグが入っていないか検証する · GitHub
こちらの記事が参考になった。