73

我们有一个高度安全的应用程序,我们希望允许用户输入其他用户可以看到的 URL。

这引入了 XSS 黑客攻击的高风险 - 用户可能会输入另一个用户最终执行的 javascript。由于我们持有敏感数据,因此永远不会发生这种情况至关重要。

处理此问题的最佳做法是什么?任何安全白名单或逃逸模式是否足够好?

关于处理重定向的任何建议(例如,在跟随链接之前的警告页面上的“此链接超出我们的站点”消息)

是否存在根本不支持用户输入链接的论点?


澄清:

基本上我们的用户想要输入:

stackoverflow.com

并将其输出给另一个用户:

<a href="http://stackoverflow.com">stackoverflow.com</a>

我真正担心的是他们在 XSS 黑客中使用它。即他们输入:

alert('被黑了!');

所以其他用户得到这个链接:

<a href="javascript:alert('hacked!');">stackoverflow.com</a>

我的例子只是为了解释风险——我很清楚 javascript 和 URL 是不同的东西,但是通过让他们输入后者,他们可能能够执行前者。

你会惊讶于这个技巧可以破坏多少个网站——HTML 更糟糕。如果他们知道处理链接,他们是否也知道清理<iframe><img>巧妙的 CSS 引用?

我在一个高度安全的环境中工作——一次 XSS 黑客攻击可能会给我们带来非常高的损失。我很高兴我可以生成一个正则表达式(或使用迄今为止最好的建议之一),它可以排除我能想到的所有内容,但这是否足够?

4

12 回答 12

59

如果您认为 URL 不能包含代码,请再想一想!

https://owasp.org/www-community/xss-filter-evasion-cheatsheet

读到,然后哭泣。

下面是我们在 Stack Overflow 上的做法:

/// <summary>
/// returns "safe" URL, stripping anything outside normal charsets for URL
/// </summary>
public static string SanitizeUrl(string url)
{
    return Regex.Replace(url, @"[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]", "");
}
于 2008-10-15T18:56:39.607 回答
17

渲染链接“安全”的过程应该经过三四个步骤:

  • 取消转义/重新编码给定的字符串(RSnake 在http://ha.ckers.org/xss.html使用转义和 UTF 编码)。
  • 清理链接:正则表达式是一个好的开始 - 如果字符串包含 " (或用于关闭输出中的属性的任何内容),请确保截断字符串或​​将其丢弃;如果您仅将链接作为参考对于其他信息,您还可以在此过程结束时强制协议 - 如果第一个冒号之前的部分不是“http”或“https”,则将“http://”附加到开头。这允许您创建可用的当用户在浏览器中键入时,来自不完整输入的链接会为您提供最后的机会,以阻止某人试图潜入的任何恶作剧。
  • 检查结果是否是格式正确的 URL (protocol://host.domain[:port][/path][/[file]][?queryField=queryValue][#anchor])。
  • 可能根据站点黑名单检查结果,或尝试通过某种恶意软件检查器获取结果。

如果安全是重中之重,我希望用户能原谅这个过程中的一些偏执,即使它最终会丢弃一些安全链接。

于 2008-10-16T20:08:37.043 回答
13

使用库,例如​​ OWASP-ESAPI API:

阅读以下:

例如:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$esapi = new ESAPI( "/etc/php5/esapi/ESAPI.xml" ); // Modified copy of ESAPI.xml
$sanitizer = ESAPI::getSanitizer();
$sanitized_url = $sanitizer->getSanitizedURL( "user-homepage", $url );

另一个例子是使用内置函数。PHP 的filter_var函数就是一个例子:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$sanitized_url = filter_var($url, FILTER_SANITIZE_URL);

Usingfilter_var 允许javascript 调用,并过滤掉既不是http也不是https. 使用OWASP ESAPI Sanitizer可能是最好的选择。

另一个例子是来自WordPress的代码:

此外,由于无法知道 URL 链接的位置(即,它可能是有效的 URL,但 URL 的内容可能是恶作剧),Google 有一个安全浏览API,您可以调用:

出于以下几个原因,滚动您自己的正则表达式进行卫生是有问题的:

  • 除非你是 Jon Skeet,否则代码会有错误。
  • 现有 API 背后有许多小时的审查和测试。
  • 现有的 URL 验证 API 考虑国际化。
  • 现有 API 将与新兴标准保持同步。

其他需要考虑的问题:

  • 您允许(file:///并且telnet://可以接受)哪些计划?
  • 您希望对 URL 的内容施加什么限制(恶意软件 URL 是否可以接受)?
于 2013-04-05T04:15:18.697 回答
4

输出链接时只需对链接进行 HTMLEncode。确保您不允许javascript:链接。(最好有一个可接受的协议白名单,例如 http、https 和 mailto。)

于 2008-10-15T18:57:01.417 回答
3

您不指定应用程序的语言,我会假设 ASP.NET,为此您可以使用Microsoft Anti-Cross Site Scripting Library

它非常易于使用,您所需要的只是一个包含,就是这样:)

当您谈到这个主题时,为什么不阅读安全 Web 应用程序的设计指南

如果有任何其他语言......如果有 ASP.NET 的库,则必须也可用于其他类型的语言(PHP、Python、ROR 等)

于 2008-10-15T18:51:47.883 回答
2

对于 Pythonistas,试试 Scrapy 的w3lib

OWASP ESAPI 早于 Python 2.7,并存档在现已失效的 Google Code上。

于 2019-03-17T10:36:20.313 回答
1

不将它们显示为链接怎么样?只需使用文本。

结合警告继续进行,风险自负可能就足够了。

另外- 另请参阅我应该清理托管 CMS 的 HTML 标记吗?有关清理用户输入的讨论

于 2008-10-15T18:49:15.393 回答
0

在我用 JavaScript 编写的项目中,我将此正则表达式用作白名单:

 url.match(/^((https?|ftp):\/\/|\.{0,2}\/)/)

唯一的限制是您需要将 ./ 放在同一目录中的文件前面,但我想我可以忍受。

于 2018-10-14T15:14:05.473 回答
0

使用正则表达式来防止 XSS 漏洞变得越来越复杂,因此随着时间的推移难以维护,同时它可能会留下一些漏洞。使用正则表达式进行 URL 验证在某些情况下很有帮助,但最好不要与漏洞检查混合使用。

解决方案可能是使用编码器的组合,例如AntiXssEncoder.UrlEncode编码 URL 的查询部分和QueryBuilder其余部分:

    public sealed class AntiXssUrlEncoder
    {
        public string EncodeUri(Uri uri, bool isEncoded = false)
        {
            // Encode the Query portion of URL to prevent XSS attack if is not already encoded. Otherwise let UriBuilder take care code it.
            var encodedQuery = isEncoded ? uri.Query.TrimStart('?') : AntiXssEncoder.UrlEncode(uri.Query.TrimStart('?'));
            var encodedUri = new UriBuilder
            {
                Scheme = uri.Scheme,
                Host = uri.Host,
                Path = uri.AbsolutePath,
                Query = encodedQuery.Trim(),
                Fragment = uri.Fragment
            };
            if (uri.Port != 80 && uri.Port != 443)
            {
                encodedUri.Port = uri.Port;
            }

            return encodedUri.ToString();
        }

        public static string Encode(string uri)
        {
            var baseUri = new Uri(uri);
            var antiXssUrlEncoder = new AntiXssUrlEncoder();
            return antiXssUrlEncoder.EncodeUri(baseUri);
        }
    }

您可能需要包含白名单以从编码中排除某些字符。这可能对特定网站有所帮助。HTML 对呈现 URL 的页面进行编码是您可能还需要考虑的另一件事。

顺便说一句。请注意,编码 URL 可能会破坏Web 参数篡改,因此编码的链接可能无法按预期工作。此外,您需要注意双重编码

PSAntiXssEncoder.UrlEncode最好命名AntiXssEncoder.EncodeForUrl为更具描述性。基本上,它对 URL 的字符串进行编码,而不是对给定的 URL 进行编码并返回可用的 URL。

于 2021-09-23T21:47:47.780 回答
0

有一个 javascript 库可以解决这个问题 https://github.com/braintree/sanitize-url 试试看 =)

于 2021-10-08T07:26:14.107 回答
-2

您可以使用十六进制代码来转换整个 URL 并将其发送到您的服务器。这样客户第一眼就不会理解内容。阅读内容后,您可以解码内容 URL = ? 并将其发送到浏览器。

于 2013-07-26T08:14:19.317 回答
-8

允许 URL 和允许 JavaScript 是两件不同的事情。

于 2008-10-15T18:48:21.900 回答