指向以 javascript:// 开头的 URL 的 link 可以执行任何代码吗?

Can a link pointing to a URL starting with javascript:// execute any code?

我发现了我正在维护的软件中的一个漏洞,用户可以将 javascript:data: link 放入内容中其他。

但是,有一种机制可以将 http:// 添加到任何不以 [a-z0-9]+:// 开头的 link href,这基本上可以只添加恶意 link 以 javascript://data:// 开头的 href。我想知道这是一个多大的安全问题,所以我的问题是,是否有任何方法可以利用此类 link 在单击它们时执行 JavaScript 代码?

我的理解是javascript:// link只能包含一个JavaScript一行注释,所以没有代码可以执行。我假设单行注释只能由换行符 (\n) 结束,但我不确定是否有办法将这样的换行符放入 link href。我尝试了不同的方法,如 href="javascript:// alert('test')"href="javascript://
alert('test')"href="javascript://%0aalert('test')" 和一个带有 [=24=] 字符的方法,但其中 none 似乎可以执行任何代码。

对于 data: URI,我想不可能组成任何以 data:// 开头的有效 URI,但也许仍然有一些浏览器可以以某种方式利用它?

我在这里提出了一些可能的问题,因为这是一个有趣的挑战。即使 none 这些工作,我认为你可以很容易地使它更安全,并且值得高枕无忧。无论如何,这是我想出的一些有效载荷。

换行

你说这对你不起作用,但它对我 Chrome (Windows 10/69.0.3497.100) 有效。这是最明显的变通方法,也是我能想到的唯一可行的变通方法。也许你在尝试时打错了字?虽然 HTML 实体编码不会这样做,但简单的 URL 编码应该......如果你的源最终看起来像这样,那么它应该可以工作:

<a href="javascript://%0aalert(document.location)">xss test</a> (jsfiddle PoC)

正则表达式不完整

你说它必须“以 [a-z0-9]+:// 开始,但正则表达式不包括“开始”部分,所以这样的东西可以匹配:

javascript:alert(1);//abc://foo.bar

您可能有类似 ^[a-z0-9]:\/\/ 的东西,或者正在使用包装“startsWith()”或类似东西的语言。值得一提。

嵌套协议

我认为这里的内容不多,但值得一看。这是您可能没有考虑过的攻击向量。

view-source://data:text/html,<script>alert(1);</script>

一方面,这不应该执行任何操作,因为它是 view-source。对于两个,它应该给出一个 CORS 错误(我认为)。最后,即使它确实执行了,它也会在与您的页面不同的上下文中执行(如果这是他们的目标,他们可能只是 link 到恶意站点)。所以周围有点虚弱。话虽这么说,也许还有其他嵌套协议可能有问题。

请求伪造

不完全是 XSS,但仍然是一个潜在问题。攻击者可能能够 link 到您网站上的现有页面,例如 https://example.com/account/delete。如果他们可以控制 link 的显示名称,这可能会很有说服力。即使他们不控制显示名称,您也可以创建一些非常混乱的 uri 来掩盖它的实际去向(各种编码技术)。您的网站上可能没有任何类似的 URL(干得好!),但它经常发生。

phishing/maliciouslinks

这可能是显而易见的,但重要的是要意识到用户可以对复制您网站(或其他网站)外观的网站进行 link。这只是允许任意 hyperlink 的普遍问题。如果您的用户群特别容易受到此影响,许多站点会将外部 link 重定向到警告页面(这可以像一点 js 一样简单地完成,例如:onclick="return confirm('you sure you want to do that?')"。虽然,我不知道这些东西到底有多有效 - 这只是你看到的东西。

结论

可能有一百万种我们可以喋喋不休地说出来的事情可能会或可能不会导致安全问题。最后,强制执行您想要允许的协议的白名单可能是值得的。您是否希望人们能够包含 link,例如 mailto:ssh:slack:file: 等?我会做一个以 http(s) 开头的客户端正则表达式,然后在后端使用 URI 解析器来确认该方案确实是 http(s),如果不是,则显示警告。这更像是一个用户体验方面的问题,但如果您担心大多数用户会输入类似“www.example.com”的内容,您可以只给他们一个客户端警告,它应该以 http(s) 开头(或者只是默认情况下有它)。对于奖励积分,也许可以考虑使用信誉检查 API 并在 url 旁边显示结果,拒绝任何信誉不佳的域。