安全漏洞问题3:跨站脚本
1.1. 漏洞描述
跨站脚本攻击(也称为XSS)指利用网站漏洞从用户端恶意盗取信息。用户在浏览网站、使用即时通讯软件、甚至在阅读电子邮件时,通常会点击其中的链接,攻击者通过在链接中插入恶意代码,系统在接收到包含恶意代码的请求之后会产成一个包含恶意代码的页面,而这个页面看起来和系统应当生成的合法页面一样,当用户浏览器显示该页面内容时即会执行攻击者插入的而恶意代码,攻击者就能够盗取用户信息。攻击者通常会用十六进制(或其他编码方式)将链接编码,以免用户怀疑它的合法性。
1.2. 漏洞危害
恶意攻击者可以通过实施跨站脚本攻击造成如下危害:
盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号
盗窃企业重要的具有商业价值的资料
实施非法转账
强制发送电子邮件
网站挂马
控制受害者机器向其它网站发起攻击
控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力
1.3. 解决方案
针对跨站脚本攻击漏洞,可以从输入或输出两个途径解决该问题,分别通过对输入数据和输出数据进行净化来防止跨站脚本攻击:
验证输入的数据类型是否正确
所有 HTTP 请求参数或 cookie 值的类型都是“字符串”。开发者应在服务器端验证输入的数据类型是否正确,检查是否可将字段值安全地转换为所需的基本数据类型。
验证数字字段(int 类型)的方式的示例:
public Class Validator {
...
public static boolean validateInt(String value) {
boolean isFieldValid = false;
try {
Integer.parseInt(value);
isFieldValid = true;
} catch (Exception e) {
isFieldValid = false;
}
return isFieldValid;
}
...
}
...
// check if the HTTP request parameter is of type int
String fieldValue = request.getParameter("fieldName");
if (Validator.validateInt(fieldValue)) {
// fieldValue is valid, continue processing request
...
}
使用白名单对输入数据进行验证
采用白名单对输入数据进行验证,在所有数据进入应用程序之前把可能的危险拦截,拒绝包含HTML特殊字符的输入,处理必须在服务器端完成。
例如,如果 userName 字段应仅允许字母数字字符,且不区分大小写,则使用以下正则表达式:^[a-zA-Z0-9]*$ 对userName字段数据进行验证。
Java 1.3 或更早的版本不包含任何正则表达式包。建议将“Apache 正则表达式包”(请参阅以下“资源”)与 Java 1.3 一起使用,以解决缺乏支持的问题。执行正则表达式验证的示例:
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
public Class Validator {
...
public static boolean matchPattern(String value, String expression) {
boolean match = false;
if (validateRequired(expression)) {
RE r = new RE(expression);
match = r.match(value);
}
return match;
}
...
}
...
// 此处校验userName
String userName = request.getParameter("userName");
if (Validator.matchPattern(userName, "^[a-zA-Z0-9]*$")) {
// userName 验证通过后的代码
...
}
使用黑名单对输入数据进行安全检查或过滤
针对非法的HTML 代码包括单双引号等,可以编写函数对其进行检查或过滤,这些处理必须在服务器端完成。需要检查或过滤的特殊字符至少包含如下表字符:
特殊/关键字符(不区分大小写)
'(单引号)
"(双引号)
<
空格键
TAB键
script
&
%
+
$
()圆括号
xss
expression
表1HTML特殊字符表
检查函数的示例代码如下:
public int XssCheck(pValue)
{
pValue = pValue.toUpperCase();
String[] strCross = {"SCRIPT","<",">",""","'","&","#",”%”,”+”,”$”,”(”,”)”," ","t","XSS","EXPRESSION"};
for(int i = 0;i
if(pValue.indexOf(strCross[i])>=0){
return 1;
//包含HTML特殊字符
}
}
return 0;
//数据不包含HTML特殊字符
}
采用开发框架自带的标签输出方式
禁止采用<% =pValue %>这种不安全的输出方式,而采用标签形式输出,如: ,采用标签方式输出时,系统在默认设置时会自动对数据做HTML转换。
对输出数据进行净化
通过过滤和转义输出数据,通过将敏感字符转换为其对应的字符实体来清理 HTML特殊字符保护应用程序免遭跨站点脚本漏洞攻击,
以下示例通过将敏感字符转换为其对应的字符实体来过滤指定字符串:
...
public static String filter(String value) {
if (value == null) {
return null;
}
StringBuffer result = new StringBuffer(value.length());
for (int i=0; i':
result.append(">");
break;
case '"':
result.append(""");
break;
case '\'':
result.append("'");
break;
case '%':
result.append("%");
break;
case ';':
result.append(";");
break;
case '(':
result.append("(");
break;
case ')':
result.append(")");
break;
case '&':
result.append("&");
break;
case '+':
result.append("+");
break;
default:
result.append(value.charAt(i));
break;
}
return result;
}
...
将Cookie设置为HttpOnly,防止被脚本获取
很多攻击都是为了获得合法用户的cookie信息,然后攻击Web应用程序。所以应该减少大量的数据存储在cookie中,在任何可能的时候使用HttpOnly cookie。
HttpOnly cookie是某些浏览器所支持的一种防御机制,许多应用程序使用它来防止XSS攻击。
当一个cookie以这种方式标记是,支持它的浏览器将阻止客户端JavaScript直接访问cookie。虽然浏览器仍然会在请求的HTTP消息头中提交这个cookie,但它不会出现在document.cookie返回的字符串中。