防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; }

@Override public void destroy() { }
@Override public void init(FilterConfig arg0) { }}

乌拉拉,这样就写完了。好,打完收工。旁边的前端妹子向我投来羡慕的眼神,我心里好乱,难道我的代码注释写的很好嘛,可我觉得一般吧。算了,不要在意这些细节,我还是去搭地铁吧。

以上是关于防sql注入过滤器的主要内容,如果未能解决你的问题,请参考以下文章

防sql注入过滤器

Struts2学习4——防sql注入过滤器

PHP防SQL注入攻击

TP5框架 《防sql注入、防xss攻击》

php如何防止sql注入

php防sql注入