消减XSS攻击的几种编码


一、实体编码

将不可信数据插入到HTML标签之间时,应对这些数据进行HTML Entity编码,具体编码对照表如下。

显示结果描述实体名称实体编号
  空格    
< 小于号 < <
> 大于号 > >
& 和号 & &
" 引号 " "
' 撇号  ' (IE不支持) '
分(cent) ¢ ¢
镑(pound) £ £
元(yen) ¥ ¥
欧元(euro)
§ 小节 § §
? 版权(copyright) © ©
? 注册商标 ® ®
? 商标
× 乘号 × ×
÷ 除号 ÷ ÷

‘——'    不推荐将单引号( ‘ )编码为 ' 因为它并不是标准的HTML标签

/ ——/

推荐使用OWASP提供的ESAPI函数库,它提供了一系列非常严格的用于进行各种安全编码的函数。HTML实体编码接口:

String encodedContent = ESAPI.encoder().encodeForHTML(request.getParameter(“input”));

二、HTML属性编码

将不可信数据插入到HTML属性里时,对这些数据进行HTML属性编码,不过需要注意的是,当要往HTML标签的事件处理属性(例如onmouseover)里插入数据的时候,应该对这些数据进行JavaScript编码。

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码。编码后输出的格式为 &#xHH; (以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符)。

可以使用ESAPI提供的函数进行HTML属性编码:

String encodedContent = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));

三、Script编码

在将不可信数据插入到script里时,对这些数据进行script编码。

主要针对动态生成的JavaScript代码,这包括脚本部分以及HTML标签的事件处理属性(Event Handler,如onmouseover, onload等)。

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \xHH (以 \x 开头,HH则是指该字符对应的十六进制数字)

可以使用ESAPI提供的函数进行JavaScript编码:



String encodedContent = ESAPI.encoder().encodeForJavaScript(request.getParameter(“input”));
四、CSS编码

当需要往Stylesheet,Style标签或者Style属性里插入不可信数据的时候,需要对这些数据进行CSS编码。传统印象里CSS不过是负责页面样式的,但是实际上它比我们想象的要强大许多,而且还可以用来进行各种攻击。因此,不要对CSS里存放不可信数据掉以轻心,应该只允许把不可信数据放入到CSS属性的值部分,并进行适当的编码。除此以外,最好不要把不可信数据放到一些复杂属性里,比如url, behavior等,只能被IE认识的Expression属性允许执行JavaScript脚本,因此也不推荐把不可信数据放到这里。



 style=” property : …插入不可信数据前,进行CSS编码… ”>

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \HH (以 \ 开头,HH则是指该字符对应的十六进制数字)

可以使用ESAPI提供的函数进行CSS编码:

String encodedContent = ESAPI.encoder().encodeForCSS(request.getParameter(“input”));
五、URL编码

当需要往HTML页面中的URL里插入不可信数据的时候,需要对其进行URL编码,如下:


[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 %HH (以 % 开头,HH则是指该字符对应的十六进制数字)

在对URL进行编码的时候,有两点是需要特别注意的:

1) URL属性应该使用引号将值部分包围起来,否则攻击者可以很容易突破当前属性区域,插入后续攻击代码

2) 不要对整个URL进行编码,因为不可信数据可能会被插入到href, src或者其他以URL为基础的属性里,这时需要对数据的起始部分的协议字段进行验证,否则攻击者可以改变URL的协议,例如从HTTP协议改为DATA伪协议,或者javascript伪协议。

可以使用ESAPI提供的函数进行URL编码:



String encodedContent = ESAPI.encoder().encodeForURL(request.getParameter(“input”));

ESAPI还提供了一些用于检测不可信数据的函数,在这里我们可以使用其来检测不可信数据是否真的是一个URL:

String userProvidedURL = request.getParameter(“userProvidedURL”);
boolean isValidURL = ESAPI.validator().isValidInput
(“URLContext”, userProvidedURL, URL”, 255, false);
if (isValidURL) 
{<a href=”<%= encoder.encodeForHTMLAttribute(userProvidedURL) %>”>
a>}

六、使用富文本时,使用XSS规则引擎进行编码过滤

Web应用一般都会提供用户输入富文本信息的功能,比如BBS发帖,写博客文章等,用户提交的富文本信息里往往包含了HTML标签,甚至是JavaScript脚本,如果不对其进行适当的编码过滤的话,则会形成XSS漏洞。但我们又不能因为害怕产生XSS漏洞,所以就不允许用户输入富文本,这样对用户体验伤害很大。

针对富文本的特殊性,我们可以使用XSS规则引擎对用户输入进行编码过滤,只允许用户输入安全的HTML标签,如, ,

等,对其他数据进行HTML编码。需要注意的是,经过规则引擎编码过滤后的内容只能放在

,

等安全的HTML标签里,不要放到HTML标签的属性值里,更不要放到HTML事件处理属性里,或者放到