处理安全性和避免使用用户输入 URL 的 XSS 的最佳方法

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

这引入了 XSS 黑客攻击的高风险——用户可能会输入其他用户最终执行的 javascript。因为我们持有敏感数据,所以这种情况绝不能发生。

处理这个问题的最佳实践是什么? 任何安全白名单或逃逸模式本身就足够好吗?

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

是否有理由不支持用户输入的链接?


澄清:

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

Stackoverflow.com

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

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

我真正担心的是他们在 XSS 黑客中使用这个,也就是说,他们输入:

警报(‘黑客入侵!’) ;

因此,其他用户得到了这个链接:

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

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

你会惊讶于有多少网站可以用这个技巧打破-HTML 是更糟糕的。如果他们知道处理链接,他们也知道消毒 <iframe><img>和聪明的 CSS 引用?

我工作在一个高度安全的环境-一个单一的 XSS 黑客可能会导致我们非常高的损失。我很高兴能够生成一个正则表达式(或者使用到目前为止最好的建议之一) ,它可以排除我能想到的所有东西,但是这就足够了吗?

62277 次浏览

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

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

再加上一个警告,让你自己承担风险可能就足够了。

附加 -参见 我是否应该清理宿主 CMS 的 HTML 标记?关于消毒用户输入的讨论

如果您不指定应用程序的语言,那么我假设您使用的是 ASP.NET,为此您可以使用 Microsoft 反跨站点脚本库

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

既然说到这个话题,为什么不读一读 安全 Web 应用程序设计指南

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

如果您认为 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+&@#/%?=~_|!:,.;\(\)]", "");
}

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

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

  • 取消转义/重新编码给定的字符串(RSnake 在 译自: 美国《科学》杂志网站(http://ha.ckers.org/xss.html) http://ha.ckers.org/xss.html : 记录了许多使用转义和 UTF 编码的技巧)。
  • 清理链接: 正则表达式是一个很好的开始-确保截断字符串或扔掉它,如果它包含一个“(或任何你用来关闭输出中的属性) ; 如果你做的链接只是作为对其他信息的引用,你也可以强制协议在这个过程的最后-如果第一个冒号之前的部分不是“ http”或“ https”,然后附加“ http://”到开始。这允许你从不完整的输入中创建可用的链接,用户可以在浏览器中输入这些链接,并给你最后一次机会,试图阻止某人试图偷偷进入的任何恶作剧。
  • 检查结果是否是格式良好的 URL (protocol://host.domain [ : port ][/path ][/[ file ]][ ? queryField = queryValue ][ # Anchor])。
  • 可能会根据站点黑名单检查结果,或者尝试通过某种恶意软件检查器获取结果。

如果安全是优先考虑的问题,我希望用户能够原谅这个过程中的一些偏执,即使它最终丢弃了一些安全链接。

使用库,例如 OWASP-ESAPI:

阅读以下内容:

例如:

$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);

使用 filter_var 允许 javascript 调用,并过滤掉既不是 http也不是 https的模式。使用 消毒剂可能是最好的选择。

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

此外,由于没有办法知道 URL 链接在哪里(例如,它可能是一个有效的 URL,但 URL 的内容可能是恶作剧) ,谷歌有一个 安全浏览 API,你可以调用:

为卫生设施编写自己的正则表达式是有问题的,原因有以下几个:

  • 除非你是 Jon Skeet,否则代码会出错。
  • 现有的 API 背后有许多小时的审查和测试。
  • 现有的 URL 验证 API 考虑国际化。
  • 现有的 API 将随着新标准的出现而不断更新。

需要考虑的其他问题:

  • 你们允许什么方案(file:///telnet://是否可以接受) ?
  • 您希望对 URL 的内容设置哪些限制(恶意软件 URL 是否可以接受) ?

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

在我用 JavaScript 编写的项目中,我使用这个 regex 作为白名单:

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

唯一的限制是你需要把。/在同一目录下的文件,但我认为我可以忍受。

对于 Python 爱好者,试试 Scrapy 的 W3lib

OWASP ESAPI 在 Python 2.7 之前就存在了,并在 现已不存在的谷歌代码上存档。

使用正则表达式来防止 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 可能会中断 网页参数篡改,因此编码后的链接可能会出现不正常的情况。 另外,还需要注意双重编码

附注: AntiXssEncoder.UrlEncode最好命名为 AntiXssEncoder.EncodeForUrl,以便更具描述性。基本上,它为 URL 编码一个字符串,而不是为给定的 URL 编码并返回可用的 URL。

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