跨站点攻击(XSS)是一个WEB应用经常面对的问题,一个安全性不好的网站,很容易就被一些低级的hacker通过xss来攻击。

在.NET里,微软有官方出品一个.NET AntiXSS Library类库,用来帮助developer简单应对跨站点攻击的问题。在java里,同样也有一个类似的类库coverity-security-library,这个类库是Coverity公司出品的。

关于Coverity公司: Coverity是开发测试行业的领头人,也是那些需要防止软件故障损害公司品牌和底线的公司的信赖标准。全球有超过1100个像Honeywell, NEC, BAE Systems, Juniper Networks, BMC Software, Samsung, France Telecom, Sega, 和 Schneider Electric这样的国际品牌依靠Coverity确保其产品和服务的质量与安全。诸多行业领先领头人利用Coverity交付高质量产品、维护竞争优势并增强客户满意度和创新能力。

类库支持

这套类库里主要有两种方式:

Escaper

Escaper是对输入的任何字符根据在Html中出现的位置不同,采用不同的转义方式,下面是类库中提供的方法以及对应的转义列表:

  • Escape.cssString(String)

    CSS string characters: ‘ (U+0022), “ (U+0027), \ (U+005C)
    HTML characters: / (U+002F), < (U+003C), > (U+003E), & (U+0026)
    Control characters: \b (U+0008), \t (U+0009), \n (U+000A), \f (U+000C), \r (U+000D)
    Unicode newlines: LS (U+2028), PS (U+2029)

  • Escape.html(String)

    HTML characters: ‘ (U+0022), “ (U+0027), \ (U+005C), / (U+002F), < (U+003C), > (U+003E), & (U+0026)
    Control characters: \t (U+0009), \n (U+000A), \f (U+000C), \r (U+000D), SPACE (U+0020)
    Unicode newlines: LS (U+2028), PS (U+2029)

  • Escape.htmlText(String)

    HTML characters: ‘ (U+0022), “ (U+0027), < (U+003C), > (U+003E), & (U+0026)

  • Escape.jsRegex(String)

    Regex characters: \ (U+005C), / (U+002F), ( (U+0028), [ (U+005B), { (U+007B), ] (U+005D), } (U+007D), ) (U+0029), * (U+002A), + (U+002B), - (U+002D), . (U+002E), ? (U+003F), ! (U+0021), ^ (U+005E), $ (U+0024), | (U+007C)
    Control characters: \t (U+0009), \n (U+000A), \v (U+000B), \f (U+000C), \r (U+000D)

  • Escape.jsString(String)

    JS String characters: ‘ (U+0022), “ (U+0027), \ (U+005C)
    URI encoding characters: % (U+0025)
    HTML characters: / (U+002F), < (U+003C), > (U+003E), & (U+0026)
    Control characters: \b (U+0008), \t (U+0009), \n (U+000A), 0x0b (U+000B), \f (U+000C), \r (U+000D)
    Unicode newlines: LS (U+2028), PS (U+2029)

  • Escape.sqlLikeClause(String)

    SQL LIKE characters: _ (U+005F), % (U+0025), @ (U+0040)

  • Escape.sqlLikeClause(String, char)

    和上面的sqlLikeClause一样,只是可以允许指定特定字符不需要转义

  • Escape.uriParam(String)

    URI characters: ‘ (U+0022), “ (U+0027), \ (U+005C), / (U+002F), < (U+003C), > (U+003E), & (U+0026), < (U+003C), > (U+003E), ! (U+0021), # (U+0023), $ (U+0024), % (U+0025), ( (U+0028), ) (U+0029), * (U+002A), + (U+002B), , (U+002C), . (U+002E), : (U+003A), ; (U+003B), = (U+003D), ? (U+003F), @ (U+0040), [ (U+005B), ] (U+005D)
    Control characters: \t (U+0009), \n (U+000A), \f (U+000C), \r (U+000D), SPACE (U+0020)

  • Escape.uri(String)

    目前实现和上面uriParam完全一样

Filter

Filter是单一转义不能满足的,对有些地方的输入是要求有特定的数据格式的,如果不符合,则转换为更安全的数据格式:

  • Filter.asCssColor(String)

    输入为颜色定义(暂时不支持rgb方式),如果输入的不是css颜色格式,则返回invalid

  • Filter.asCssColor(String, String)

    同上,第二个参数为默认值,即,如果输入不是可识别的颜色格式,则返回默认值

  • Filter.asNumber(String)

    只接受八进制、十进制、十六进制的数字型内容,如不是,则返回0

  • Filter.asNumber(String, String)

    同上asNumber,如果不能,则返回默认值(第二个参数)

  • Filter.asURL(String)

    对URL进行判断,如果schema为http|https|ftp|mailto则返回,否则返回相对路径(在input前面添加./

  • Filter.asFlexibleURL(String)

    对URL进行判断,如果schema不为javascript|vbscript|data|about,则返回输入,否则返回相对路径(在input前面添加./

如何使用

使用时,根据出现的位置不同,使用不同的方法。唯一的区别是java代码和jsp代码中有些区别。

在jsp中,需要使用对应的jsp EL,如下:

<%@ taglib uri="http://coverity.com/security" prefix="cov" %>

<script type="text/javascript">
var x = '${cov:jsStringEscape(param.tainted)}';
</script>
<div onclick="alert('${cov:htmlEscape(cov:jsStringEscape(param.tainted))}')">
${cov:htmlEscape(param.tainted)}
</div>

java代码中,按下面方式使用:

import com.coverity.security.Escape;

return "<div onclick='alert(\""
+ Escape.html(Escape.jsString(request.getParameter("tainted")))
+ "\")'>"
+ Escape.html(request.getParameter("tainted"))
+ "</div>";

使用时,需根据要转义代码出现的位置来使用,如果同时满足多个条件,则需要使用复合形式,如在a标签里href里出现的javascript代码,它满足:

  1. 在html属性里
  2. 在url的位置上
  3. 是javascript代码的一部分

这种情况则需要按照下面的方式才能输入更安全的代码:

<a href="javascript:hello('${cov:htmlEscape(cov:uriEncode(cov:jsStringEscape(content)))}')">

参考