目录
目的
实现步骤
完整代码
目的
在Springboot中创建过滤器,用来过滤所有POST类型请求并获取body中的参数进行校验内容是否合法;该方法仅适用于POST类型请求,因为POST和GET请求的参数位置不一样所以处理方式也不一样,如果想要实现拦截获取GET类型请求校验参数,可以参考以下示例:
Springboot中拦截GET请求获取请求参数验证合法性https://blog.csdn.net/weixin_45151960/article/details/132184917?spm=1001.2014.3001.5501
实现步骤
1、创建Filter过滤器用来过滤所有请求;
2、将PSOT类型请求中的body参数内容进行转换;
3、处理body数据进行校验:
3.1、当body数据仅为json对象时进行处理校验;
3.2、当body数据仅为json数组时进行处理校验;
3.3、当body数据为json对象且包含json数组时进行处理校验;
3.4、当body数据为json数组且包含json对象时进行处理校验;
完整代码
过滤器
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.boc.ljh.utils.Result;
import com.boc.ljh.utils.status.AppErrorCode;
import org.springframework.context.annotation.Configuration;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** @Author: ljh* @ClassName SqlFilter* @Description 过滤请求内容 防止sql注入* @date 2023/8/8 16:15* @Version 1.0*/@WebFilter(urlPatterns = "/*", filterName = "sqlFilter")
@Configuration
public class SqlFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) servletResponse;response.setContentType("application/json;charset=utf-8");Result result = new Result();result.setStatus(500);result.setMessage(AppErrorCode.REQUEST_DATA_FULL.message);String data = JSON.toJSONString(result);BodyReaderRequestWrapper wrapper = null;HttpServletRequest request = (HttpServletRequest) servletRequest;if (request.getMethod().equals("POST")) {String contentType = request.getContentType();if ("application/json".equals(contentType)) {wrapper = new BodyReaderRequestWrapper(request);String requestPostStr = wrapper.getBody();if (requestPostStr.startsWith("{")) {//解析json对象boolean b = resolveJSONObjectObj(requestPostStr);if (!b) {response.getWriter().print(data);return;}} else if (requestPostStr.startsWith("[")) {//把数据转换成json数组JSONArray jsonArray = JSONArray.parseArray(requestPostStr);List<String> list = JSONObject.parseArray(jsonArray.toJSONString(), String.class);for (String str : list) {if (str.startsWith("{")) {//解析json对象boolean b = resolveJSONObjectObj(requestPostStr);if (!b) {response.getWriter().print(data);return;}} else {boolean b = verifySql(str);if (b) {try {response.getWriter().print(data);return;} catch (IOException e) {e.printStackTrace();}}}}}} else {//application/x-www-form-urlencodedMap<String, String[]> parameterMap = request.getParameterMap();for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {//校验参数值是否合法String[] value = entry.getValue();for (String s : value) {//校验参数值是否合法boolean b = verifySql(s);if (b) {response.getWriter().print(data);return;}}}}}if (wrapper == null) {filterChain.doFilter(servletRequest, servletResponse);} else {filterChain.doFilter(wrapper, servletResponse);}}/*** @Author: ljh* @Description: 对JSONObject对象进行递归参数解析* @DateTime: 14:26 2023/8/9* @Params:* @Return*/private boolean resolveJSONObjectObj(String requestPostStr) {boolean isover = true;// 创建需要处理的json对象JSONObject jsonObject = JSONObject.parseObject(requestPostStr);// 获取所有的参数keySet<String> keys = jsonObject.keySet();if (keys.size() > 0) {for (String key : keys) {//获取参数名称String value;if (jsonObject.get(key) != null) {value = String.valueOf(jsonObject.get(key));//当value为数组时if (value.startsWith("[")) {//把数据转换成json数组JSONArray jsonArray = JSONArray.parseArray(value);for (Object o : jsonArray) {if (o.toString().startsWith("{")) {//解析json对象boolean b = resolveJSONObjectObj(o.toString());if (!b) {isover = false;break;}} else {boolean b = verifySql(value);if (b) {isover = false;break;}}}} else if (value.startsWith("{")) {boolean b = resolveJSONObjectObj(value);if (!b) {isover = false;break;}} else {//校验参数值是否合法boolean b = verifySql(value);if (b) {isover = false;break;}}}}}return isover;}@Overridepublic void destroy() {}/*** @Author: ljh* @Description: 校验参数非法字符* @DateTime: 14:26 2023/8/9* @Params:* @Return*/public boolean verifySql(String parameter) {String s = parameter.toLowerCase();// 过滤掉的sql关键字,特殊字符前面需要加\\进行转义String badStr ="select|update|and|or|delete|insert|truncate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|table|" +"char|declare|sitename|xp_cmdshell|like|from|grant|use|group_concat|column_name|" +"information_schema.columns|table_schema|union|where|order|by|" +"'\\*|\\;|\\-|\\--|\\+|\\,|\\//|\\/|\\%|\\#";//使用正则表达式进行匹配boolean matches = s.matches(badStr);return matches;}}
解析body数据 工具类
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;/*** @Author: ljh* @ClassName BodyReaderRequestWrapper* @Description 解析body数据* @date 2023/8/8 16:14* @Version 1.0*/public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {private final String body;public String getBody() {return body;}/*** 取出请求体body中的参数(创建对象时执行)** @param request*/public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException {super(request);StringBuilder sb = new StringBuilder();InputStream ins = request.getInputStream();BufferedReader isr = null;try {if (ins != null) {isr = new BufferedReader(new InputStreamReader(ins));char[] charBuffer = new char[128];int readCount;while ((readCount = isr.read(charBuffer)) != -1) {sb.append(charBuffer, 0, readCount);}}} finally {if (isr != null) {isr.close();}}sb.toString();body = sb.toString();}@Overridepublic BufferedReader getReader() {return new BufferedReader(new InputStreamReader(this.getInputStream()));}@Overridepublic ServletInputStream getInputStream() {final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() {return byteArrayIns.read();}};}
}