处理安全性的最佳方法,并避免使用用户输入的URL进行XSS

时间:2008-10-15 18:46:52

标签: security url xss html-sanitizing

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

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

处理此问题的最佳做法是什么?单独的安全白名单或转义模式是否足够好?

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

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


澄清:

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

  

stackoverflow.com

并将其输出给其他用户:

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

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

  

警报( '黑客攻击!');

所以其他用户可以获得此链接:

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

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

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

我在高安全性环境中工作 - 单个XSS黑客可能会给我们造成很大的损失。我很高兴我可以制作一个正则表达式(或使用迄今为止的优秀建议之一),可以排除我能想到的所有内容,但这还够吗?

10 个答案:

答案 0 :(得分:54)

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

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

阅读,然后哭泣。

以下是我们如何在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+&@#/%?=~_|!:,.;\(\)]", "");
}

答案 1 :(得分:13)

将链接呈现为“安全”的过程应该经历三个或四个步骤:

  • Unescape /重新编码您已经获得的字符串(RSnake在 http://ha.ckers.org/xss.html记录了许多使用转义和UTF编码的技巧。
  • 清理链接:正则表达式是一个好的开始 - 如果它包含“(或者用于关闭输出中的属性的任何内容),请确保截断字符串或​​将其丢弃;如果您正在执行链接仅作为对其他信息的引用,您也可以在此过程结束时强制执行协议 - 如果第一个冒号之前的部分不是'http'或'https',则在开头附加'http://'。这允许您从用户输入的浏览器中输入不完整输入的可用链接,并为你提供最后一次尝试绊倒某人试图偷偷摸摸的恶作剧。
  • 检查结果是否格式​​正确(protocol://host.domain [:port] [/ path] [/ [file]] [?queryField = queryValue] [#anchor])。
  • 可能会针对网站黑名单检查结果,或尝试通过某种恶意软件检查程序获取结果。

如果安全是一个优先事项,我希望用户在这个过程中会原谅一点偏执,即使它最终会丢掉一些安全链接。

答案 2 :(得分:8)

使用库,例如​​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);

使用filter_var allows个javascript调用,过滤掉既不是http也不是https的方案。使用OWASP ESAPI Sanitizer可能是最佳选择。

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

此外,由于无法知道URL链接的位置(即,它可能是有效的URL,但URL的内容可能是恶作剧的),因此Google可以调用safe browsing API:

由于以下几个原因,将自己的正则表达式用于卫生设施是有问题的:

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

需要考虑的其他问题:

  • 您允许哪些方案(file:///telnet://可接受?)
  • 您希望对网址内容施加哪些限制(可接受的恶意软件网址)?

答案 3 :(得分:3)

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

它非常易于使用,您只需要一个包含就可以了:)

当你谈论这个话题时,为什么不在Design Guidelines for Secure Web Applications上阅读

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

答案 4 :(得分:3)

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

答案 5 :(得分:1)

如何不将它们显示为链接?只需使用文字。

结合警告以自行承担风险可能就足够了。

添加 - 另请参阅Should I sanitize HTML markup for a hosted CMS?有关清理用户输入的讨论

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

对于Pythonista用户,请尝试Scrapy的w3lib

OWASP ESAPI pre-dates Python 2.7,并保存在now-defunct Google Code上。

答案 8 :(得分:-1)

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

答案 9 :(得分:-7)

允许使用URL并允许使用JavaScript是两回事。