防sql注入过滤器
Posted Fantasy小平
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了防sql注入过滤器相关的知识,希望对你有一定的参考价值。
上一篇文章中弄完了xss过滤器,今天来弄一下防sql注入的过滤器。为什么呢?我怎么知道为什么,去问问产品经理/客户吧。总之,像这种安全性的过滤器,就像一个藤上的葫芦娃一样,一个接着一个的出现。平时没有啥作用,但关键时候来个合体,能将邪恶的大魔王挡在门外。
现在后端的框架也做了防止sql注入的手段,比如使用PreparedStatement+占位符。但加一层过滤器总归更加安全一点。这里的防sql注入的过滤器可以对普通get/post请求进行参数过滤,也可以对post+application/json等请求进行参数过滤。该过滤器使用了请求的包装类,具体参考我的上一篇文章。
好,现在是代码时刻,把这个防sql注入过滤器放在xss过滤器之前。为什么呢?因为xss过滤器会把一些字符进行转义,这个时候如果再进行防sql注入的过滤,就会让该过滤器以为是sql注入的请求,就会报错。
package cn.wjp.mydaily.common.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import javax.servlet.FilterConfig;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
/**
* 防止SQL注入的拦截器 放在xssFilter之后 xssFilter转义之后的字符会被该过滤器当作sql注入
* @author wjp
*
*/
public class SqlInjectFilter implements Filter {
/**
* 需要过滤的sql关键字,可以手动添加
*/
public static final String BAD_PARAM_STR ="'|and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|" +
"char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|" +
"table|from|grant|use|group_concat|column_name|" +
"information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
"chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#";
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request =(HttpServletRequest)req;
HttpServletResponse response =(HttpServletResponse)res;
String contentType = request.getContentType();//获取contentType请求头
String method = request.getMethod();//获取请求方法 post/get
//1 处理get请求 get请求的Content-Type一般为application/x-www-form-urlencoded 或者 text/html
if(method.trim().equalsIgnoreCase(HttpConst.GET_METHOD)){
if(isValidParamForGet(request)){
chain.doFilter(request, response);
return;
}else {
response.sendError(403,"发送的参数可能会引起sql注入,系统拒绝服务!");
return;
}
}
//2 处理post请求 只处理application/x-www-form-urlencoded application/json,对于multipart/form-data,直接放行
if(method.trim().equalsIgnoreCase(HttpConst.POST_METHOD)){
if(contentType.trim().toLowerCase().contains(HttpConst.MULTIPART_CONTENT_TYPE)){
chain.doFilter(request, response);
return;
}
//处理application/x-www-form-urlencoded
if(contentType.trim().toLowerCase().contains(HttpConst.FORM_URLENCODED_CONTENT_TYPE)){
if(isValidParamForPost(request)){
chain.doFilter(request, response);
return;
}else {
response.sendError(403,"发送的参数可能会引起sql注入,系统拒绝服务!");
return;
}
}
//处理application/json
if(contentType.trim().toLowerCase().contains(HttpConst.JSON_CONTENT_TYPE)){
HttpServletRequestBodyReaderWrapper wrapperRequest = new HttpServletRequestBodyReaderWrapper(request);
String body = wrapperRequest.getBody();
if(isValidParamForJsonPost(body)){
chain.doFilter(wrapperRequest, response);
return;
}else {
response.sendError(403,"发送的参数可能会引起sql注入,系统拒绝服务!");
return;
}
}
}
chain.doFilter(request, response);
return;
}
//sql注入效验
protected static boolean isSqlValidate(String str) {
if(str==null||str.trim().isEmpty()){
return true;
}
str = str.toLowerCase();//统一转为小写
String[] badStrs = BAD_PARAM_STR.split("\\|");
for (int i = 0; i < badStrs.length; i++) {
if (Pattern.matches("^"+badStrs[i]+"$",str)) {
return false;
}
}
return true;
}
/**
* get请求的参数是否无害 无害:true 有害:false
* @param request
* @return
*/
public boolean isValidParamForGet(HttpServletRequest request){
Enumeration params = request.getParameterNames();//获得所有请求参数名
System.out.println("SqlInjectFilter:发送的请求参数值串:"+params);
while (params.hasMoreElements()) {
String name = params.nextElement().toString(); //得到参数名
String[] value = request.getParameterValues(name);//得到参数对应值
if(!isSqlValidate(name)){
return false;
}
for (int i = 0; i < value.length; i++) {
if(!isSqlValidate(value[i])){
return false;
}
}
}
return true;
}
/**
* post请求的参数是否无害 无害:true 有害:false
* @param request
* @return
*/
public boolean isValidParamForPost(HttpServletRequest request){
return isValidParamForGet(request);
}
/**
* post请求的参数是否无害 无害:true 有害:false
* @param body 请求体
* @return
*/
public boolean isValidParamForJsonPost(String body){
System.out.println("SqlInjectFilter:发送的请求参数值串:"+body);
if(body==null||body.trim().isEmpty()||body.trim().equalsIgnoreCase("{}")||!body.trim().contains(":")){
return true;
}
Map<String,Object> map = JSON.parseObject(body,new TypeReference<Map<String,Object>>(){});
if(map==null||map.size()==0){
return true;
}
for (Map.Entry<String,Object> entry : map.entrySet()) {
String key = entry.getKey();
if(!isSqlValidate(key)){
return false;
}
Object value = entry.getValue();
String valueStr = String.valueOf(value);
if(valueStr==null||valueStr.trim().isEmpty()||valueStr.trim().equalsIgnoreCase("null")){
valueStr = null;
}
if(!isSqlValidate(valueStr)){
return false;
}
}
return true;
}
public void destroy() {
}
public void init(FilterConfig arg0) {
}
}
乌拉拉,这样就写完了。好,打完收工。旁边的前端妹子向我投来羡慕的眼神,我心里好乱,难道我的代码注释写的很好嘛,可我觉得一般吧。算了,不要在意这些细节,我还是去搭地铁吧。
以上是关于防sql注入过滤器的主要内容,如果未能解决你的问题,请参考以下文章