指向以javascript://开头的URL的链接能执行任何代码吗?

3

我发现一个我正在维护的软件中存在漏洞,用户可以在其他人看到的内容中添加 javascript: 和 data: 链接。

但是,已经有一个机制,如果任何链接href不以 [a-z0-9] +:// 开头,则会将 http:// 添加到该链接href前缀,这基本上使得只能添加以 javascript:// 或 data:// 开头的恶意链接href。 我想知道这有多大的安全问题,我的问题是,是否有任何方法可以利用这样的链接在单击它们时执行JavaScript代码?

我的理解是, javascript:// 链接只能包含一个JavaScript单行注释,因此不能执行任何代码。 我认为一行注释只能以换行符( \ n )结束,但我不确定是否有办法将这样的换行符带入链接href中。 我尝试了不同的方法,如 href =“javascript:// alert('test')”, href =“javascript://
alert('test')”, href =“javascript://%0aalert('test')”以及带有 \ 0 字符的链接href,但没有一种方法似乎可以执行任何代码。

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


1
href="javascript:(function() { anything goes here and will be executed in scope of current page })()" - mplungjan
就此而言,看起来Chrome会从URL中清除换行符,因为访问链接的.href属性会产生"javascript://alert('test')"。而在a.getAttribute('href')中则存在换行符。 - AKX
同时确保不能将 #" onclick="anything goes here" 添加到 href 中。 - mplungjan
@mplungjan:谢谢,HTML字符已经被转义了。您编写的JavaScript链接未以javascript://开头 - cdauth
不确定你是否可以在你的软件中使用它,但添加内容安全策略将使得javascript:链接更难以工作(你不应该仅依赖它,适当的转义是更好的选择,但这是一个很好的额外措施)。 - Bergi
1个回答

1
我提出了几个可能的问题,因为这是一个有趣的挑战。即使没有这些解决方案,我认为你可以很容易地使其更安全,并且它会值得放心。无论如何,这是一些我想到的有效负载。
新行
你说这对你不起作用,但在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错误(我想)。最后,即使它确实执行了,它也将在与您的页面不同的上下文中执行(如果他们的目标是链接到恶意站点,那么他们可以这样做)。总的来说,有点薄弱。话虽如此,也许还有其他可能会有问题的嵌套协议。
请求伪造
不完全是XSS,但仍然存在潜在问题。攻击者可能能够链接到您网站上现有的页面,例如https://example.com/account/delete。如果他们可以控制链接的显示名称,这可能会让人相信这是真实的。即使他们不能控制显示名称,您也可以创建一些非常混乱的URI来掩盖它实际要去的地方(各种编码技术)。您的网站上可能没有任何类似的URL(做得好!),但这种情况经常发生。
钓鱼/恶意链接
这可能很明显,但重要的是要意识到用户可以创建一个链接到模仿您网站外观的站点(或其他站点)的站点。这只是允许任意超链接的一般关注点。如果您的用户群体特别容易受到此影响,则许多站点将外部链接重定向到警告页面(这可以简单地通过一些js完成,例如:onclick="return confirm('you sure you want to do that?')。尽管如此,我不知道这些东西实际上有多有效-这只是您看到的一些东西。
结论

我们可以列举可能会导致安全问题的无数事情。最终,强制执行白名单来允许哪些协议可能是值得的。您是否希望用户能够包含像mailto:ssh:slack:file:等链接?我建议在客户端使用正则表达式以http(s)开头,然后在后端使用URI解析器确认方案是否确实为http(s),如果不是,则提供警告。这更多是用户体验方面的考虑,但如果您担心大多数用户会输入类似于“www.example.com”的内容,您可以给他们一个客户端警告,提示它应该以http(s)开头(或默认情况下就有)。对于额外加分,也许考虑使用声誉检查API并将结果与URL一起呈现,拒绝任何声誉不佳的域。


1
感谢您详细的回答!确实,我通过使用您的%0a方法成功地利用了它。我认为之前我没有成功的原因是,在应用程序中,由于某种原因,URL被解码了,所以我必须对换行符进行双重编码(%250a)。 - cdauth
啊,有趣。一定要确认解码过程不允许存储型XSS攻击。例如:%22%20%2F%3E%3Csvg%20onload%3Dalert%281%29%2F%3E => "/> <svg onload=alert(1)/> - Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接