危险的encodeURIComponent

简介:

javascript中的 encodeURIComponent() 方法很常用,MDN里在描述这个方法的时候,有提到这个异常: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

在下面这个case中,node.js里被发现一个严重bug: http://cnodejs.org/topic/4fd6b7ba839e1e581407aac8
当时所有connect的app都紧急修复大伙们之前都没有意识到这个问题的存在,直到遇到这个可怕的0xDFFF,实在是隐蔽,汗!

stackoverflow上有人给出了一个详细的解答,大致翻译一下,大伙看看:

同样也是遇到这个问题,为了发现问题所在,@Brett Zamir 写了一个遍历方法,把ucs-2的字符集扫描了一遍:

for (var regex = '/[', firstI = null, lastI = null, i = 0; i <= 65535; i++) {
    try {
        encodeURIComponent(String.fromCharCode(i));
    }
    catch(e) {
        if (firstI !== null) {
            if (i === lastI + 1) {
                lastI++;
            }
            else if (firstI === lastI) {
                regex += '\\u' + firstI.toString(16);
                firstI = lastI = i; 
            }
            else {
                regex += '\\u' + firstI.toString(16) + '-' + '\\u' + lastI.toString(16);
                firstI = lastI = i; 
            }
        }
        else {
            firstI = i;
            lastI = i;
        }        
    }
}

if (firstI === lastI) {
    regex += '\\u' + firstI.toString(16);
}
else {
    regex += '\\u' + firstI.toString(16) + '-' + '\\u' + lastI.toString(16);
}
regex += ']/';
alert(regex);  // /[\ud800-\udfff]/

很快结果就出来了,ud800-udfff 这段的字符是有问题的,再写个脚本验证一下:

for (var i = 0; i <= 65535 && (i <0xD800 || i >0xDFFF ) ; i++) {
    try {
        encodeURIComponent(String.fromCharCode(i));
    }
    catch(e) {
        alert(e); // Doesn't alert
    }
}
alert('ok!');

上面的输出符合MSDN上说的:这些字符除了surrogates,即便是“non-characters”也都是合法的unicode序列。

surrogates就是上面扫描出来的危险字符集空间段,分为高位段,低位段

有了这个范围,你可以直接过滤掉这些危险字符,但是当这组字符成对出现的时候(高低位段的字符搭配),它们作为unicode扩展集字符又是合法的(utf-16)

alert(encodeURIComponent('\uD800\uDC00')); // ok
alert(encodeURIComponent('\uD800')); // not ok
alert(encodeURIComponent('\uDC00')); // not ok either

所以如果你只是想屏蔽这个段的字符

urlPart = urlPart.replace(/[\ud800-\udfff]/g, '');

如果你想屏蔽非法的字符,但是保留高低位合法组合的字符(utf-16字符,很少用到),可以这么搞:

function stripUnmatchedSurrogates (str) {
    return str.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])/g, '').split('').reverse().join('').replace(/[\uDC00-\uDFFF](?![\uD800-\uDBFF])/g, '').split('').reverse().join('');
}

var urlPart = '\uD801 \uD801\uDC00 \uDC01'
alert(stripUnmatchedSurrogates(urlPart)); // Leaves one valid sequence (representing a single

如果js native处理了这个问题,就可以免了这个猥琐的修补,多好啊,哼!

====== 翻译完毕 ====

补充:

上诉的高低位端,实际上是 UCS-2中的保留字段。 unicode字符集分为很多端,看这里 http://baike.baidu.com/view/40801.htm

D800-DBFF:High-half zone of UTF-16  utf-16 高位
DC00-DFFF:Low-half zone of UTF-16  utf-16 低位

utf-16的参考资料:http://zh.wikipedia.org/wiki/UTF-16, 其中描述到:

Unicode的编码空间从U+0000到U+10FFFF,共有1,112,064个码位(code point)可用来映射字符. Unicode的编码空间可以划分为17个平面(plane),每个平面包含216(65,536)个码位。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面。第一个平面称为基本多语言平面(Basic Multilingual Plane, BMP),或称第零平面(Plane 0)。其他平面称为辅助平面(Supplementary Planes)。基本多语言平面内,从U+D800到U+DFFF之间的码位区段是永久保留不映射到Unicode字符。UTF-16就利用保留下来的0xD800-0xDFFF区段的码位来对辅助平面的字符的码位进行编码。

所以这个问题就清晰明了

补充: 感谢 @猎隼 的补充
decodeURIComponent()确实也是危险的存在, js的encodeURIComponent, decodeURIComponent 处理的都是utf-8编码的字符集。decodeURIComponent 一旦传入gbk的encode字符串,异常就会抛出,没有try catch就会搞死node进程。

参考:
http://stackoverflow.com/questions/16868415/encodeuricomponent-throws-an-exception

目录
相关文章
|
6月前
|
前端开发 JavaScript 安全
【网络安全/前端XSS防护】一文带你了解HTML的特殊字符转义及编码
【网络安全/前端XSS防护】一文带你了解HTML的特殊字符转义及编码
418 0
|
6月前
|
安全 JavaScript 前端开发
escape, encodeURI, encodeURIComponent 有什么区别以及作用?
escape, encodeURI, encodeURIComponent 有什么区别以及作用?
307 0
|
6月前
都是编码函数escape、encodeURI、encodeURIComponent有啥区别?
都是编码函数escape、encodeURI、encodeURIComponent有啥区别?
|
SQL 编解码 前端开发
urldecode()解码引发注入其实也没那么可怕
urldecode()解码引发注入其实也没那么可怕
180 0
urldecode()解码引发注入其实也没那么可怕
|
存储 开发框架 安全
目标URL存在跨站漏洞
目标URL存在跨站漏洞
806 0
目标URL存在跨站漏洞
|
存储 Web App开发 JavaScript
xss攻击、绕过最全总结
简述 XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
2052 0
|
安全
一文助你分清encodeURI与encodeURIComponent
帮助你区别 encodeURI 与 encodeURIComponent 的使用场景
750 0
|
存储 安全 JavaScript
如何修复网站XSS漏洞 过滤script等攻击参数来解决
很多公司的网站维护者都会问,到底什么XSS跨站漏洞?简单来说XSS,也叫跨站漏洞,攻击者对网站代码进行攻击检测,对前端输入的地方注入了XSS攻击代码,并写入到网站中,使用户访问该网站的时候,自动加载恶意的JS代码并执行,通过XSS跨站漏洞可以获取网站用户的cookies以及seeion值,来窃取用户的账号密码等等的攻击行为,很多客户收到了网警发出的信息安全等级保护的网站漏洞整改书,说网站存在XSS跨站漏洞,客户找到我们SINE安全公司寻求对该漏洞的修复以及解决。
3342 0
XSS三重URL编码绕过实例
遇到一个很奇葩的XSS,我们先来加一个双引号,看看输出:  双引号被转义了,我们对双引号进行URL双重编码,再看一下输出:  依然被转义了,我们再加一层URL编码,即三重url编码,再看一下输出:   URL编码被还原为双引号,并带入到html中输入。
2025 0