为什么在 'javascript:' URL 中间使用 TAB (%09) 字符有效?

信息安全 网页浏览器 xss
2021-09-01 09:02:08

一些上下文:我在一次渗透测试中被分配,并找到了一个应用程序,可以让我将自己的链接放置在a标签的href属性中。正如预期的那样,所有奇怪的值javascript:都被 XSS 过滤器正确过滤了,但是我发现你可以通过在协议规范中间注入一个 TAB 字符来绕过这个过滤器,如下所示:

<a href="javascri   pt:alert(1)"></a>

现在我想知道的是,为什么浏览器会接受这是一个有效的 javscript URL,它会愉快地执行代码,而其他字符(如 SPACE 字符)是不允许的?他们允许这种奇怪的格式有历史原因吗?


注意:在 Chrome 上测试过,对于那些喜欢测试它的人,它也可以window.location像这样工作:

window.location.href = 'javascr\x09ipt:alert(1)'
2个回答

当一个元素被点击时,链接被跟随并且它的 URL 被解析。这会导致字符串由基本 URL 解析器处理。

在您的示例中,参数在路径状态下处理,在此期间 TAB (U+0009) 字符以及回车和换行字符被忽略,因此不构成解析 URL 的一部分。为什么锚标记会删除 href 属性内指定的 URL 中的制表符?

根据基本 URL 解析器的规范,ASCII 制表符或换行符将从 URL 中删除(或只是忽略)。

我发现了一个旧的讨论,你可能会觉得有趣,以了解这种选择背后可能的历史原因。

https://bugzilla.mozilla.org/show_bug.cgi?id=87298

这是 Mozilla 中存在 19 年历史的错误。问题是一个网站没有按预期工作,因为 Mozilla 没有在链接的 URL 中去除制表符。该页面在 Internet Explorer 中按预期工作,显然忽略了选项卡。制表符通常用于 HTML 文件中的缩进,因此有时您可以期待在换行后有几个制表符。有人引用了 IETF 标准,建议“在提取 URI 时应忽略空格”。但是,其他人并不完全相信删除所有空白字符会是一个好主意,因为有时您可能会遇到带有未编码空格的 URI(例如:https://www.example.com/path with spaces/),即使这是错误的,至少根据当前标准。因此,他们决定只在已删除字符列表中添加制表符(回车和换行字符已被删除)。请注意,当空格位于 URI 的开头或结尾时(例如:<a href=" http://www.example.com "></a>),允许并忽略空格。

所以我想这个选择的历史原因是他们想确保下面的代码可以工作:

<!-- URL with new lines and TABS for indentation -->
<a href="https://www.example.com/?
         param1=foo&
         param2=bar">
   Click on this example link
</a>

<!-- URL with unencoded spaces -->
<a href="https://www.example.com/path with spaces/foo">Click here</a>

然而,他们并没有检查 URL 中空格或制表符的确切位置,他们只是决定保留空格并删除制表符。因此,如果您使用空格进行缩进,第一个示例将不起作用,并且制表符可以包含在 URL 中的任何位置而不会影响任何内容(因此即使是java<tab>script也可以)。