对于Web系统,要防范Sql注入|XSS(跨站脚本攻击)等其他攻击,一般处理方法是针对攻击的关键子进行过滤。这里针对Sql注入和XSS攻击防范方法提供使用的说明。
一、Sql注入防范
1、过滤Sql关键字
大家都知道Web服务器核心实现就是Servlet技术,servlet的过滤器可以对请求Header,请求内容等进行过滤和修改。Sql注入就是利用过滤器功能对请求参数的关键字进行过滤处理,从而降低Sql注入的成功率。
- 创建过滤器实现Filter接口,web.xml配置过滤器信息
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper{
@Override
publicvoid doFilter(ServletRequest request, ServletResponse response,FilterChainchain) throws IOException, ServletException {
HttpServletRequesthttpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
XssHttpServletRequestWrapperxssReq = new XssHttpServletRequestWrapper(httpRequest);
chain.doFilter(xssReq, response);
}
}
- 创建一个包装器类,继承HttpServletRequestWrapper类
下面是这个类具体实现,这里运用了装饰模式,建议大家先了解下该模式具体内容,可以参考:《JAVA与模式》之装饰模式
这里最重要的是stripXSS()方法,利用正则表达式过滤特殊关键字,其他的方法都是套路,按照它的要求实现即可。如果对正则表达式不是很了解,可以参考:正则表达式30分钟入门教程。
publicclass XssHttpServletRequestWrapper extends HttpServletRequestWrapper{
private Map params;
HttpServletRequestorgReq = null;
publicXssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.orgReq= request;
this.params= request.getParameterMap();
}
@Override
public Map getParameterMap() {
return params ;
}
@Override
public Enumeration getParameterNames() {
Vector l = new Vector(params.keySet());
return l.elements();
}
@Override
public String[] getParameterValues(Stringname) {
Object v = params.get(name);
if (v == null ) {
return null ;
} else if (v instanceof String[]) {
String[] value = (String[])v;
for (int i = 0; i <value.length; i++) {
value[i] =stripXSS(value[i]);
}
return (String[]) value;
} else if (v instanceof String) {
String value = (String) v;
value = stripXSS(value);
return new String[] {(String) value };
} else {
return new String[] {v.toString() };
}
}
@Override
public String getParameter(String name) {
Object v = params.get(name);
if (v == null ) {
return null ;
} else if (v instanceof String[]) {
String[] strArr =(String[]) v;
if (strArr.length > 0){
String value =strArr[0];
// value =stripXSS(value);
returnstripXSS(value);
} else {
return null ;
}
} else if (v instanceof String) {
String value = (String) v;
// value = stripXSS(value);
return stripXSS(value);
} else {
return v.toString();
}
}
// 使用正则替换关键字
privateString stripXSS(String value) {
if (value != null) {
// NOTE: It's highly recommended touse the ESAPI library and uncomment the following line to
// avoid encoded attacks.
// value =ESAPI.encoder().canonicalize(value);
// Avoid null characters
value =value.replaceAll("", "");
// Avoid anything between scripttags
Pattern scriptPattern =Pattern.compile("<script>(.*?)</script>",Pattern.CASE_INSENSITIVE);
value =scriptPattern.matcher(value).replaceAll("");
// Avoid anything in asrc="http://www.yihaomen.com/article/java/..." type of expression
// scriptPattern =Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value =scriptPattern.matcher(value).replaceAll("");
// scriptPattern =Pattern.compile("(?:')|(?:--)(/\\*(?:.[\\n\\r])*?\\*/)'",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value =scriptPattern.matcher(value).replaceAll("");
// scriptPattern =Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value =scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome</script> tag
scriptPattern =Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
value =scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome <script...> tag
scriptPattern =Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE |Pattern.MULTILINE | Pattern.DOTALL);
value =scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern =Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE |Pattern.MULTILINE | Pattern.DOTALL);
value =scriptPattern.matcher(value).replaceAll("");
// Avoid expression(...)expressions
scriptPattern =Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE |Pattern.MULTILINE | Pattern.DOTALL);
value =scriptPattern.matcher(value).replaceAll("");
// Avoid javascript:...expressions
scriptPattern =Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
value =scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern =Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
value =scriptPattern.matcher(value).replaceAll("");
// Avoid οnlοad= expressions
scriptPattern =Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE |Pattern.MULTILINE | Pattern.DOTALL);
value =scriptPattern.matcher(value).replaceAll("");
// (select .* from)
//scriptPattern =Pattern.compile("(^(?!.*?select?.).*select|udpate|delete.*|(\n|\r)from)", Pattern.CASE_INSENSITIVE);
scriptPattern =Pattern.compile("(insert|select|udpate|delete|\\s+or|\\s+and|\\s+drop)\\s+",Pattern.CASE_INSENSITIVE);
value =scriptPattern.matcher(value).replaceAll("");
// insert into
scriptPattern =Pattern.compile("(insert.*into)", Pattern.CASE_INSENSITIVE);
value =scriptPattern.matcher(value).replaceAll("");
scriptPattern =Pattern.compile("(\b(and|trancate|ascii|declare|exec|count|master|drop|execute)\b)",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
value =scriptPattern.matcher(value).replaceAll("");
}
return value;
}
}
2、程序中使用PreparedStatement替代sql拼接
一般公司对编码规范没有明确规定,很多人为了图方便,在编写sql时直接采用字符串拼接方式,这样倒是省事,但无疑留下了一个巨坑,容易导致sql注入攻击。
很多规范要求采用PreparedStatement对象的方法,对传入的参数采用占位符方式来避免sql注入攻击。
PreparedStatement有预编译的过程,已经绑定sql,之后无论执行多少遍,都不会再去进行编译,所以性能比Statement要好,而且可以有效的防止 SQL注入等问题