详谈XSS防御方法


  1、HttpOnly 严格的说,httponly并非为了对抗XSS,它解决的是XSS后的Cookie劫持攻击。Cookie设置了httponly之后,JavaScript读不到该cookie的值。 一个cookie的使用过程如下: step1:浏览器向服务器发起请求,这时候没有cookie step2:服务器返回时发送set-cookie头,向客户端浏览器写入cookie step3:在该cookie到期前,浏览器访问该域下的所有页面,都将发送该cookie HttpOnly是在set-cookie时标记的:
Set-Cookie: =[; <Max-Age>=]
[; expires=<date>][; domain=]
[; path=][; secure][; HttpOnly]
HttpOnly可以有选择性地加在任何一个cookie值上:在某些时候,应用可能需要JavaScript访问某几项cookie,这种cookie可以不设置HttpOnly标记,而仅把HttpOnly标记给用于认证的关键cookie 举个例子:  
<?php
header("Set-Cookie: cookie1=test1;");
header("Set-Cookie: cookie2=test2;httponly",false);
?>
 
  在这段代码中,cookie1没有HttpOnly,cookie2被标记为HttpOnly,两个cookie均被写入浏览 但是只有cookie1被JavaScript读取到: 这就是HttpOnly的作用。     2、输入检查   输入检查的逻辑,必须放在服务器端代码中实现。如果只是在客户端使用JavaScript进行输入检查,是很容易被攻击者绕过的。目前Web开发的普遍做法,是同时在客户端JavaScript中和服务器端代码中实现相同的输入检查。客户端JavaScript的输入检查,可以阻挡大部分误操作的用户,从而节约服务器资源。   3、输出检查   一般来说,除了富文本的输出外,在变量输出到HTML页面时,可以使用编码或转义的方式来防御XSS攻击。 针对HTML代码的编码方式是HtmlEncode HtmlEncode并非专有名词,它只是一种函数实现。它的作用是将字符转化成HTMLEntities。 为了对抗XSS,在HtmlEncode中要求至少转换一下字符: &    -->   & <    -->   < >    -->   > "     -->   " '      -->   '           $apos;不推荐 /     -->   /            包含斜杠是因为它可能会闭合一些HTML entity 在PHP中,有htmlentities()和htmlspecialchars()两个函数可以满足安全要求。 htmlspecialchars — 将特殊字符转换为 HTML 实体 htmlentities — 将字符转换为 HTML 转义字符,本函数各方面都和 htmlspecialchars() 一样, 除了 htmlentities() 会转换所有具有 HTML 实体的字符。   相应地,JavaScript的编码方式可以使用JavaScriptEncode JavaScriptEncode与HtmlEncode的编码方式不同,它需要使用反斜杠"\"对特殊字符进行转义。 在对抗XSS时,还要求输出的变量必须在引号内部,以避免造成安全问题。比较下面两种写法:
var x = escapeJavascript($evil);
var y = '"'+escapeJavascript($evil)+'"';
如果escapeJavascript()函数只转义了几个危险字符,比如 ' "  <  >  \   &  #  等,那么上面的两行代码输出后可能会变成:
var x = 1;alert(2);
var y = "1;alert(2)";
第一行执行了额外的代码了;第二行则是安全的。对于后者,攻击者即使想要逃逸出引号的范围,也会遇到困难:
var y = "\";alert(1);\/\/";
所以要求JavaScript的变量输出一定要在引号内。 可是很多开发者没有这个习惯怎么办?这就只能使用一个更加严格的JavaScriptEncode函数来保证安全——除了数字、字母外的所有字符,都使用十六进制“\xHH”的方式进行编码。 在本例中: var x = 1;alert(2); 变成了: var x = 1\x3balert\x282\x29; 如此代码可以保证是安全的。   此外,XSS是很复杂的问题,需要"在正确的地方使用正确的编码方式"。 举个例子:

# onclick="alert('$var');" >test
开发者希望看到的结果是,用户点击链接后,弹出变量"$var"的内容。可是如果用户输入: $var = htmlencode("');alert('2"); 对变量"$var"进行htmlencode后,渲染的结果是:

# onclick="alert('');alert('2');">test
对于浏览器来说,htmlparser会优先于JavaScript Parser执行,所以解析过程是,被HtmlEncode的字符先被解码,然后执行JavaScript事件。 因此,经过htmlparser解析后相当于:

# onclick="alert('');alert('2');">test
成功在onclick事件中注入了XSS代码。 第一次弹框 第二次弹框 导致XSS攻击发送的原因,是由于没有分清楚输出变量的语境。   4、正确地防御XSS   XSS的本质还是一种"HTML注入",用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义。 下面将用变量"$var"表示用户数据,它将被填充入HTML代码中。可能存在以下场景。   (1)、在HTML标签中输出
$var
# >$var
所有在标签中输出的变量,如果未做任何处理,都能导致直接产生XSS。 在这种场景下,XSS的利用方式一般是构造一个
或者 # > 防御方法是对变量使用HtmlEncode   (2)、在HTML属性中输出
$var" >
与在HTML标签中输出类似,可能的攻击方式是:
<"">
防御方法也是采用HtmlEncode 在OWASP ESAPI中推荐了一种更严格的HtmlEncode——除了字母、数字外,其他所有的特殊字符都被编码成HTMLEntities
String safe = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter("input"));
这种严格的编码方式,可以保证不会出现任何安全问题。   (3)、在 攻击者需要先闭合引号才能实施XSS攻击:
防御时使用JavascriptEncode   (4)、在事件中输出 在事件中输出和在 点击标签的链接,将导致执行脚本。   由此可见,如果用户能够完全控制URL,则可以执行脚本的方式有很多。如果解决这种情况呢? 一般来说,如果变量是整个URL,则应该先检查变量是否以"http"开头(如果不是则自动添加),以保证不会出现伪协议类的XSS攻击。 test 在此之后,再对变量进行URLEncode,即可保证不会再有此类的XSS发生了。   5、处理富文本   有些时候,网站需要允许用户提交一些自定义的HTML代码,称之为“富文本”。 过滤富文本时,“事件”应该被严格禁止,因为“富文本”的展示要求里不应该包含“事件”这种动态效果。而一些危险的标签,比如