diff options
-rw-r--r-- | include/text.php | 12 | ||||
-rw-r--r-- | tests/unit/AntiXSSTest.php | 20 |
2 files changed, 32 insertions, 0 deletions
diff --git a/include/text.php b/include/text.php index 9a2ca1af4..0c806d009 100644 --- a/include/text.php +++ b/include/text.php @@ -114,6 +114,18 @@ function escape_tags($string) { return (htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false)); } +/** + * Escape URL's so they're safe for use in HTML and in HTML element attributes. + */ +function escape_url($input) { + if (empty($input)) { + return EMPTY_STR; + } + + // This is a bit crude but seems to do the trick for now. It makes no + // guarantees that the URL is valid for use after escaping. + return htmlspecialchars($input, ENT_HTML5 | ENT_QUOTES); +} function z_input_filter($s,$type = 'text/bbcode',$allow_code = false) { diff --git a/tests/unit/AntiXSSTest.php b/tests/unit/AntiXSSTest.php index b45042a1e..09642726f 100644 --- a/tests/unit/AntiXSSTest.php +++ b/tests/unit/AntiXSSTest.php @@ -24,6 +24,26 @@ class AntiXSSTest extends TestCase { $this->assertEquals("<submit type="button" onclick="alert('failed!');" />", $escapedString); } + /** + * @dataProvider urlTestProvider + */ + public function testEscapeURL($url, $expected) : void { + $this->assertEquals($expected, escape_url($url)); + } + + public function urlTestProvider() : array { + return [ + [ + "https://example.com/settings/calendar/?f=&rpath=https://example.com/cdav/calendar'><script>alert('boom')</script>", + "https://example.com/settings/calendar/?f=&rpath=https://example.com/cdav/calendar'><script>alert('boom')</script>" + ], + [ + "settings/calendar/?f=&rpath=https://example.com'+accesskey=x+onclick=alert(/boom/);a='", + "settings/calendar/?f=&rpath=https://example.com'+accesskey=x+onclick=alert(/boom/);a='" + ], + ]; + } + /** *xmlify and unxmlify */ |