几种极其隐蔽的XSS注入的防护

XSS注入的本质就是: 某网页中根据用户的输入, 不期待地生成了可执行的js代码, 并且js得到了浏览器的执行. 意思是说, 发给浏览器的字符串中, 包含了一段非法的js代码, 而这段代码跟用户的输入有关.

常见的XSS注入防护,可以通过简单的htmlspecialchars(转义HTML特殊字符),strip_tags(清除HTML标签)来解决,但是,还有一些隐蔽的XSS注入不能通过这两个方法来解决,而且,有时业务需要不允许清除HTML标签和特殊字符.下面列举几种隐蔽的XSS注入方法:

IE6/7UTF7XSS漏洞攻击

隐蔽指数:5

伤害指数:5

这个漏洞非常隐蔽,因为它让出现漏洞的网页看起来只有英文字母(ASCII字符),并没有非法字符,htmlspecialchars和strip_tags函数对这种攻击没有作用.不过,这个攻击只对IE6/IE7起作用,从IE8起微软已经修复了.你可以把下面这段代码保存到一个文本文件中(前面不要有空格和换行),然后用IE6打开试试(没有恶意代码,只是一个演示):

+/v8+ADw-script+AD4-alert(document.location)+ADw-/script+AD4-

最容易中招的就是JSONP的应用了,解决方法是把非字母和数字下划线的字符全部过滤掉.还有一种方法是在网页开始输出空格或者换行,这样,UTF7-XSS就不能起作用了.

因为只对非常老版本的IE6/IE7造成伤害,对Firefox/Chrome没有伤害,所以伤害指数只能给4颗星.

参考资料:UTF7-XSS

不正确地拼接JavaScript/JSON代码段

隐蔽指数:5

伤害指数:5

Web前端程序员经常在PHP代码或者某些模板语言中,动态地生成一些JavaScript代码片段,例如最常见的:

vara='<?phpechohtmlspecialchars($name);?>';

不想,$name是通过用户输入的,当用户输入a’;alert(1);时,就形成了非法的JavaScript代码,也就是XSS注入了.

在解决问题之前,我们要思考问题的本质是什么?本质在于程序员可以用字符串来控制整个世界,却没有用正确的方法来生成正确的字符串,而是采用了功能强大且原始的”手工字符串拼接”.

只需要把上面的代码改成:

vara=<?phpechojson_encode($name);?>;

去掉单引号,利用PHP的json_encode()函数来生成表示字符串的字符串.这样做是因为,最好用json_encode()函数来生成所有的JSON串,而不要试图自己去拼接.程序员总是犯这样的错误:自己去解析HTTP报文,而不是用现成的成熟的库来解析.用json_encode()的好处还在于,即使业务要求”我要保留单引号”时,XSS注入也可以避免.

隐蔽指数最高级,伤害所有的通用浏览器.这种XSS注入方式具有非常重要的参考意义.

最后,根据工作中的经验,以及我自己和别人犯过的错,我总结出一个定理:没有一劳永逸的单一方法可以解决所有XSS注入问题.

有用的经验:

输出HTML代码时htmlspecialchars

输出JavaScript代码时json_encode

输入过滤应该用于解决业务限制,而不是用于解决XSS注入(与严进宽出的原则相悖,所以本条值得讨论)

讨论:

上文提到的经验第3条,是一种”宽进严出”的原则,和”严进宽出”原则是相悖的.其实,我认为不应该把”严进宽出”作为一条伪真理,好像除了它其它的说法都不对了似的.“宽进严出”和”严进宽出”应该具有完全相等的地位,根据实现的成本进行取舍.

例如,用户的名字可以采用”严进宽出”原则,不允许用户填写单引号,大于号小于号等.但是用户的签名呢?难道就不能填单引号?如果要走极端,想找出一种银弹,那么我能想到的就是对所有的输入一律进行htmlspecialchars和json_encode(且不说解决不了utf7-xss).

其实,XSS注入的解决应该是和输出端相关的.当需要输出到文本文件时,过滤和转义都是无必要的.当输出到HTML渲染引擎时,json_encode是无必要的.当输出到JS引擎时,htmlspecialchars是无必要的.

xss

相关推荐