From 9f29fb7a47e9960a2eca962b0f2f26901078d143 Mon Sep 17 00:00:00 2001 From: Kentaro Ohkouchi Date: Fri, 22 Nov 2024 17:04:14 +0900 Subject: [PATCH 1/5] Use HTMLpurifier --- composer.json | 1 + composer.lock | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 275105ad0d..e646c05455 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "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", diff --git a/composer.lock b/composer.lock index 4972347145..ecf4a361e6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,69 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "636ee3a24be4e148cef2625409af2b8c", + "content-hash": "15a7f16df843568f4448bf26756c4bdd", "packages": [ + { + "name": "ezyang/htmlpurifier", + "version": "v4.18.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0" + }, + "time": "2024-11-01T03:51:45+00:00" + }, { "name": "mobiledetect/mobiledetectlib", "version": "3.74.3", From f942d2b9959e4056cf0b2faf4aabb65868d0440b Mon Sep 17 00:00:00 2001 From: Kentaro Ohkouchi Date: Fri, 22 Nov 2024 17:07:07 +0900 Subject: [PATCH 2/5] =?UTF-8?q?default=20modifiers=20=E3=81=AB=20HTMLPurif?= =?UTF-8?q?ier=20=E3=82=92=E9=81=A9=E7=94=A8=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/smarty_extends/modifier.script_escape.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/data/smarty_extends/modifier.script_escape.php b/data/smarty_extends/modifier.script_escape.php index 99885cd382..3d14551bb1 100644 --- a/data/smarty_extends/modifier.script_escape.php +++ b/data/smarty_extends/modifier.script_escape.php @@ -1,4 +1,5 @@ set('Cache.SerializerPath', __DIR__ . '/../cache'); + $purify = new HTMLPurifier($config); + + return $purify->purify($value ?? ''); } From 016c309ab28e636bb7211ea9675bfe50f52db936 Mon Sep 17 00:00:00 2001 From: Kentaro Ohkouchi Date: Fri, 22 Nov 2024 17:56:27 +0900 Subject: [PATCH 3/5] =?UTF-8?q?default=20pattern=20=E3=81=AE=E3=82=B5?= =?UTF-8?q?=E3=83=8B=E3=82=BF=E3=82=A4=E3=82=BA=E3=81=AE=E3=81=82=E3=81=A8?= =?UTF-8?q?=E3=80=81HTMLPurifier=20=E3=81=AB=E3=82=88=E3=81=A3=E3=81=A6?= =?UTF-8?q?=E5=AE=8C=E5=85=A8=E3=81=AB=E5=89=8A=E9=99=A4=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E5=A0=B4=E5=90=88=E3=81=8C=E3=81=82=E3=82=8B=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modifier/Modifier_ScriptEscapeTest.php | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/class/modifier/Modifier_ScriptEscapeTest.php b/tests/class/modifier/Modifier_ScriptEscapeTest.php index fa35449aba..dfdf8b5ca2 100644 --- a/tests/class/modifier/Modifier_ScriptEscapeTest.php +++ b/tests/class/modifier/Modifier_ScriptEscapeTest.php @@ -5,73 +5,73 @@ * * PHP 8.1 でグローバル変数が消失する不具合を回避するため、下で `backupGlobals` を指定している。本質的には PHPUnit が PHP8 に対応していないのが原因と考えられる。 * - * @backupGlobals disabled */ class Modifier_ScriptEscapeTest extends PHPUnit_Framework_TestCase { public function scriptEscapeProvider() { + $default_pattern = '/#script escaped#/'; return [ - [''], - ['test'], - ['test'], - ['test'], - [''], - [''], - [''], - ['\"onclick=\"alert(1)\"'], - ['

test

'], - ['

test

'], - ['

test

'], - [''], - [''], - [''], - [''], - ['
'], - ['
javascript:test()
'], - [''], - [''], - [''], - ['
'], - [''], - [''], - [''], - [''], - ['
'], + ['', $default_pattern], + ['test', $default_pattern], + ['test', $default_pattern], + ['test', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['\"onclick=\"alert(1)\"', $default_pattern], + ['

test

', $default_pattern], + ['

test

', $default_pattern], + ['

test

', $default_pattern], + ['', '//'], // HTMLPurifier によって完全に削除される + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['
', $default_pattern], + ['
javascript:test()
', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', $default_pattern], + ['', '//'], // HTMLPurifier によって完全に削除される + ['
', $default_pattern], ]; } public function scriptNoEscapeProvider() { return [ - ['

test

'], - [''], - ['

onclick

'], - ['
test
'], - [''], - ['

onclick="\ntest();"

'], - ['test

', '

test

'], + ['', ''], // 許可タグではないのでHTMLPurifier によって完全に削除される + ['

onclick

', '

onclick

'], + ['
test
', '
test
'], + ['', 'onclick="alert(1)";'], // 許可タグではないのでHTMLPurifierによって textarea タグが削除される + ['

onclick="\ntest();"

', '

onclick="\ntest();"

'], + ['assertMatchesRegularExpression($pattern, $ret); } /** * @dataProvider scriptNoEscapeProvider */ - public function testメールテンプレートエスケープされない($value) + public function testメールテンプレートエスケープされない($value, $actual) { $ret = smarty_modifier_script_escape($value); $pattern = '/#script escaped#/'; $this->assertDoesNotMatchRegularExpression($pattern, $ret); + $this->assertSame($ret, $actual); } } From 1cc948175822abdeff9e95242f40b598aa569705 Mon Sep 17 00:00:00 2001 From: Kentaro Ohkouchi Date: Sat, 23 Nov 2024 23:46:48 +0900 Subject: [PATCH 4/5] =?UTF-8?q?id=20=E5=B1=9E=E6=80=A7=E3=81=8C=E3=82=B5?= =?UTF-8?q?=E3=83=8B=E3=82=BF=E3=82=A4=E3=82=BA=E3=81=95=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=9F=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit id 属性が重複するとよろしくないが、厳密にサニタイズするよりも後方互換 性を優先する --- data/smarty_extends/modifier.script_escape.php | 1 + tests/class/modifier/Modifier_ScriptEscapeTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/data/smarty_extends/modifier.script_escape.php b/data/smarty_extends/modifier.script_escape.php index 3d14551bb1..edcd623c77 100644 --- a/data/smarty_extends/modifier.script_escape.php +++ b/data/smarty_extends/modifier.script_escape.php @@ -54,6 +54,7 @@ function smarty_modifier_script_escape($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 ?? ''); diff --git a/tests/class/modifier/Modifier_ScriptEscapeTest.php b/tests/class/modifier/Modifier_ScriptEscapeTest.php index dfdf8b5ca2..15c44e4c11 100644 --- a/tests/class/modifier/Modifier_ScriptEscapeTest.php +++ b/tests/class/modifier/Modifier_ScriptEscapeTest.php @@ -44,7 +44,7 @@ public function scriptEscapeProvider() public function scriptNoEscapeProvider() { return [ - ['

test

', '

test

'], + ['

test

', '

test

'], ['', ''], // 許可タグではないのでHTMLPurifier によって完全に削除される ['

onclick

', '

onclick

'], ['
test
', '
test
'], From b67346109d0504cd93adbc476f41e0c7a1845925 Mon Sep 17 00:00:00 2001 From: Kentaro Ohkouchi Date: Tue, 17 Dec 2024 10:35:18 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/class/modifier/Modifier_ScriptEscapeTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/class/modifier/Modifier_ScriptEscapeTest.php b/tests/class/modifier/Modifier_ScriptEscapeTest.php index 15c44e4c11..27f1f029e6 100644 --- a/tests/class/modifier/Modifier_ScriptEscapeTest.php +++ b/tests/class/modifier/Modifier_ScriptEscapeTest.php @@ -2,9 +2,6 @@ /** * (省略。アノテーションを認識されるのに必要なようなので記述している。) - * - * PHP 8.1 でグローバル変数が消失する不具合を回避するため、下で `backupGlobals` を指定している。本質的には PHPUnit が PHP8 に対応していないのが原因と考えられる。 - * */ class Modifier_ScriptEscapeTest extends PHPUnit_Framework_TestCase {