3

我正在尝试缓解 XSS。我怎样才能避免这种情况:

j&#X41vascript:alert('test2')

href一个链接?

我尝试了以下方法,但它只是将上述字符串的文字、未解析值分配为 href 的相对路径,而不是javascript:能够触发代码执行的正确 href。我想知道攻击者如何能够利用它。

我尝试了以下方法:

a = document.createElement('a');

然后这两个:

a.href = 'j&#X41vascript:alert('test2')';

还有这个:

a.setAttribute('href', "j&#X41vascript:alert('test2')");

但是两者都"j&#X41vascript:alert('test2')"在查询时返回a.href,而不是期望的(或不期望的,取决于您的观点)javascript:alert('test2');

如果我可以让所有实体解析,那么我可以解析出javascript:结果字符串中所有出现的 ,并且是安全的——对吗?

我在想的另一件事是,如果有人这样做怎么办jvascript:steal_cookie();。我的意思是,从理论上讲,它们可以具有无限的递归级别,并且最终都会解决,对吗?


编辑:这段代码看起来如何?

function resolve_entities(str) {
  var s = document.createElement('span')
    , nestTally = str.match(/&/) ? 0 : 1
    , limit = 5
    , limitReached = false;

  s.innerHTML = str;
  while (s.textContent.match(/&/)) {
    s.innerHTML = s.textContent;
    if(nestTally++ >= limit) {
      limitReached = true;
      break;
    }
  }

  return s.textContent;
}
4

3 回答 3

4

当包含它们的字符串被解析为 XML 或 HTML 时, XML/HTML 字符实体类似于A&被解码。通常,当它们作为 HTML 页面的一部分从服务器发送到浏览器时会发生这种情况,尽管还有其他情况(例如在 JavaScript 中分配给)可能导致字符串被解析为 XML 或 HTML。element.innerHTML

在 JavaScript 中读取或写入元素属性不会触发 XML/HTML 解析,因此不会扩展字符实体。如果你写

a.href = "jAvascript:alert('test')";

那么该元素的href属性a将是jAvascript:alert('test'), & 和所有。

需要注意的重要一点是,每当将字符串解析为 XML 或 HTML 时,字符实体都会被解码一次。因此,&x41;变为a,而A变为A。它不会“最终全部解决”,除非您正在做一些愚蠢的事情,例如反复阅读.textContent和分配给。.innerHTML

解析完成后,输出中的任何字符序列是否看起来像 XML/HTML 字符实体完全无关紧要——也就是说,除非您随后获取输出并再次通过 XML/HTML 解析器提供它。(这样做很少有用,而且通常只是由于诸如分配给.innerHTML何时应该分配给之类的错误而发生.textContent。)


无论如何,看看评论,你说你正在编写一些客户端 JavaScript 代码,这些代码从你无法控制的服务器获取一些不受信任的数据,并且你担心简单地将数据分配给.innerHTML可能允许 XSS 攻击。如果是这样,有两种情况:

  1. 您收到的数据是纯文本。在这种情况下,您应该将其分配给它.textContent并完成它。

  2. 实际上,您收到的数据是 HTML。在这种情况下,您确实需要承担对其进行消毒的艰巨而费力的工作。 这个来自 Caja 项目的 JavaScript HTML sanitizer可能会有所帮助。

于 2012-09-08T15:12:19.303 回答
2

只要内容格式正确,就可以使用 XML 安全地解析它。像这样的东西,至少作为一个起点(小提琴):

function getXmlDoc(s) {
    var parser;
    if(DOMParser){
        parser = new DOMParser();
        xmlDoc = parser.parseFromString(s, "text/xml");
    } else {
        // IE
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = false;
        xmlDoc.loadXML(s); 
    }
    return xmlDoc;
}

var xml = getXmlDoc("<root>j&#x0061;vascript:alert('test2')</root>");
alert(xml.documentElement.firstChild.nodeValue);

​</p>

但是,我可能只是逃避不安全的字符:

function safeEscape(s) {
    return s.replace(/[\&\<\>]/g, function($0) {
        switch($0) {
            case '&': return '&amp;';
            case '<': return '&lt;';
            case '>': return '&gt;';
        }
    });
}

您不应该遇到递归转义字符的任何问题,因为这是不允许的。

于 2012-09-08T13:58:50.107 回答
2

缓解 XSS 的最佳方法是使用适合输出所在上下文(HTML、HTML 属性、CSS、JS 等)的适当编码方法对呈现到屏幕的所有不受信任的输出进行编码。

即使您设法解决了这个问题,也可能存在其他使用您没有想到的编码的攻击媒介。黑名单过滤器很少(如果有的话)是保护您的网站的最有效方法。

我不确定您使用的是哪种服务器端语言,但可能有它的编码库。ESAPI可用于多种语言,并且是为此目的而构建的(以及许多其他语言)。

更新:由于您需要为此使用 JavaScript,您可能需要查看ESAPI Encoding Project (Reform)。它有一个 JS 版本,看起来可以满足您的需求。我没有测试过它,但如果它像 ESAPI 一样工作,那么它可能会解决你的问题。

要了解有关每个上下文正确编码的更多信息,请查看OWASP XSS 预防备忘单

于 2012-09-08T14:03:40.487 回答