Skip to content

Commit

Permalink
Revert "想定しない脆弱性を防ぐため default modifier に HTMLPurifier を適用する"
Browse files Browse the repository at this point in the history
  • Loading branch information
nanasess authored Dec 23, 2024
1 parent 2fe0c3a commit 73dae8e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 110 deletions.
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"php": "^7.4 || ^8.0",
"ext-gd": "*",
"ext-mbstring": "*",
"ezyang/htmlpurifier": "^4.18",
"mobiledetect/mobiledetectlib": "^3.74",
"nanasess/mdb2": "^2.5",
"nanasess/php8-compat": "^1.0",
Expand Down
63 changes: 1 addition & 62 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 1 addition & 8 deletions data/smarty_extends/modifier.script_escape.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?php
require_once __DIR__.'/../vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php';
/**
* Scriptタグをエスケープする
*
Expand Down Expand Up @@ -51,11 +50,5 @@ function smarty_modifier_script_escape($value)
$value = preg_replace($pattern, $convert, $value);
}

// 念のために HTMLPurifier でサニタイズ
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.SerializerPath', __DIR__.'/../cache');
$config->set('Attr.EnableID', true); // id 属性はサニタイズしない
$purify = new HTMLPurifier($config);

return $purify->purify($value ?? '');
return $value;
}
80 changes: 41 additions & 39 deletions tests/class/modifier/Modifier_ScriptEscapeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,76 @@

/**
* (省略。アノテーションを認識されるのに必要なようなので記述している。)
*
* PHP 8.1 でグローバル変数が消失する不具合を回避するため、下で `backupGlobals` を指定している。本質的には PHPUnit が PHP8 に対応していないのが原因と考えられる。
*
* @backupGlobals disabled
*/
class Modifier_ScriptEscapeTest extends PHPUnit_Framework_TestCase
{
public function scriptEscapeProvider()
{
$default_pattern = '/#script escaped#/';

return [
['<script type="text/javascript"></script>', $default_pattern],
['<svg onload="alert(1)">test</svg>', $default_pattern],
['<img onload="alert(1)">test</img>', $default_pattern],
['<body onload="alert(1)">test</body>', $default_pattern],
['<iframe></iframe>', $default_pattern],
['<object></object>', $default_pattern],
['<embed>', $default_pattern],
['\"onclick=\"alert(1)\"', $default_pattern],
['<p onclick="alert(1)">test</p>', $default_pattern],
['<p onsubmit="alert(1)">test</p>', $default_pattern],
['<p style="" onclick="alert(1)">test</p>', $default_pattern],
['<input type="button"onfocus="alert(1)">', '//'], // HTMLPurifier によって完全に削除される
['<input type="button" onblur="alert(1)">', $default_pattern],
['<input onfocus="alert(1)" type="button">', $default_pattern],
['<body onresize="alert(1)">', $default_pattern],
['<div onscroll="alert(1)">', $default_pattern],
['<div>javascript:test()</div>', $default_pattern],
['<input type="button" ondblclick="alert(1)">', $default_pattern],
['<input type="text" onchange="alert(1);">', $default_pattern],
['<input type="text" onselect="alert(1);">', $default_pattern],
['<form onsubmit="alert(1);">', $default_pattern],
['<input type="button" onkeydown="alert(1)">', $default_pattern],
['<input type="button" onkeypress="alert(1)">', $default_pattern],
['<input type="button" onkeyup="alert(1)">', $default_pattern],
['<input type=\"button\"\nonclick=\"alert(1)\">', '//'], // HTMLPurifier によって完全に削除される
['<div/onscroll="alert(1)">', $default_pattern],
['<script type="text/javascript"></script>'],
['<svg onload="alert(1)">test</svg>'],
['<img onload="alert(1)">test</img>'],
['<body onload="alert(1)">test</body>'],
['<iframe></iframe>'],
['<object></object>'],
['<embed>'],
['\"onclick=\"alert(1)\"'],
['<p onclick="alert(1)">test</p>'],
['<p onsubmit="alert(1)">test</p>'],
['<p style="" onclick="alert(1)">test</p>'],
['<input type="button"onfocus="alert(1)">'],
['<input type="button" onblur="alert(1)">'],
['<input onfocus="alert(1)" type="button">'],
['<body onresize="alert(1)">'],
['<div onscroll="alert(1)">'],
['<div>javascript:test()</div>'],
['<input type="button" ondblclick="alert(1)">'],
['<input type="text" onchange="alert(1);">'],
['<input type="text" onselect="alert(1);">'],
['<form onsubmit="alert(1);">'],
['<input type="button" onkeydown="alert(1)">'],
['<input type="button" onkeypress="alert(1)">'],
['<input type="button" onkeyup="alert(1)">'],
['<input type=\"button\"\nonclick=\"alert(1)\">'],
['<div/onscroll="alert(1)">'],
];
}

public function scriptNoEscapeProvider()
{
return [
['<p id="test" class="test">test</p>', '<p id="test" class="test">test</p>'],
['<input type="button">', ''], // 許可タグではないのでHTMLPurifier によって完全に削除される
['<p>onclick</p>', '<p>onclick</p>'],
['<div>test</div>', '<div>test</div>'],
['<textarea>onclick="alert(1)";</textarea>', 'onclick="alert(1)";'], // 許可タグではないのでHTMLPurifierによって textarea タグが削除される
['<p>onclick="\ntest();"</p>', '<p>onclick="\ntest();"</p>'],
['<onclock', ''], // 許可タグではないのでHTMLPurifier によって完全に削除される
['<oncl\nick', ''], // 許可タグではないのでHTMLPurifier によって完全に削除される
['<p>test</p>'],
['<input type="button">'],
['<p>onclick</p>'],
['<div>test</div>'],
['<textarea>onclick="alert(1)";</textarea>'],
['<p>onclick="\ntest();"</p>'],
['<onclock'],
['<oncl\nick'],
];
}

/**
* @dataProvider scriptEscapeProvider
*/
public function testメールテンプレートエスケープされる($value, $pattern)
public function testメールテンプレートエスケープされる($value)
{
$ret = smarty_modifier_script_escape($value);
$pattern = '/#script escaped#/';
$this->assertMatchesRegularExpression($pattern, $ret);
}

/**
* @dataProvider scriptNoEscapeProvider
*/
public function testメールテンプレートエスケープされない($value, $actual)
public function testメールテンプレートエスケープされない($value)
{
$ret = smarty_modifier_script_escape($value);
$pattern = '/#script escaped#/';
$this->assertDoesNotMatchRegularExpression($pattern, $ret);
$this->assertSame($ret, $actual);
}
}

0 comments on commit 73dae8e

Please sign in to comment.