Skip to content

Instantly share code, notes, and snippets.

@iseebi
Created August 20, 2018 04:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iseebi/126f246271dadf1ad73ee02b422b36d2 to your computer and use it in GitHub Desktop.
Save iseebi/126f246271dadf1ad73ee02b422b36d2 to your computer and use it in GitHub Desktop.
[PHP] 入力されたHTMLにscriptタグが入っていないか検証する
<?php
namespace App\Model\Validation;
use Cake\Validation\Validation;
use DOMDocument;
class HtmlInputValidation extends Validation
{
/**
* セキュアでないHTMLが入力されていないか確認する
* <script> タグと on から始まる属性が入っている場合はセキュアでないとする。
* @param $value
* @return bool
*/
public static function isSecureHtml($value)
{
if (empty($value)) {
return true;
}
$domDocument = new DOMDocument();
$domDocument->loadHTML($value);
$xmlString = $domDocument->saveXML();
$xmlObject = simplexml_load_string($xmlString);
return HtmlInputValidation::validateNode($xmlObject->body);
}
/**
* isSecureHtml の再帰処理関数
* @param $node \SimpleXMLElement
* @return bool
*/
private static function validateNode($node)
{
foreach ($node->attributes() as $name => $attr) {
if ((strlen($name)) > 1 && (strtolower(substr($name, 0, 2)) == 'on')) {
var_dump($name);
return false;
}
}
foreach ($node->children() as $child) {
$name = $child->getName();
if (strtolower($name) == 'script') {
return false;
}
if (!HtmlInputValidation::validateNode($child)) {
return false;
}
}
return true;
}
}
<?php
namespace App\Model\Table;
class SampleTable extends Table
{
public function validationDefault(Validator $validator)
{
$validator->setProvider('HtmlInput', 'App\Model\Validation\HtmlInputValidation');
$validator
->scalar('text')
->requirePresence('text', 'create')
->notEmpty('text')
->add('body1', 'htmlSecure', [
'rule' => ['isSecureHtml'],
'provider' => 'HtmlInput',
'message' => '不正なタグが入力されています',
]);
}
}
<?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!";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment