Java 杂谈计算机杂谈

2019-08-23/防sql注入过滤器

2019-08-23  本文已影响2人  呼噜噜睡

现在后端的框架也做了防止sql注入的手段,比如使用PreparedStatement+占位符。但加一层过滤器总归更加安全一点。这里的防sql注入的过滤器可以对普通get/post请求进行参数过滤,也可以对post+application/json等请求进行参数过滤。
该过滤器使用了请求的包装类,具体参考我的上一篇文章https://www.jianshu.com/p/579558b6dc63
,这里只给出过滤参数的部分:

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
 * @time 20190425
 */
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) {
    }
}

上一篇 下一篇

猜你喜欢

热点阅读