springboot防止sql注入,springboot怎么防止sql注入
目录
1.过滤器SqlInjectFilter2 .请求装饰类CustomRequestWrapper3 .过滤器注册4.测试辅助类4.1 结果对象ResultObj4.2 Restful的控制器类5.测试5.1员额请求测试5.2获取请求测试15.3获取请求测试注射毒品场景:以过滤器(过滤器)的方式,对所有超文本传送协议(超文本传输协议的缩写)请求的入参拦截,使用正则表达式匹配入参中的字符串。存在结构化查询语言注入风险的参数,中断请求,并立即返回提示信息。不存在结构化查询语言注入风险的参数,校验通过后,放入过滤器链,继续后续业务。
环境:本例是基于跳羚的网工程,版本:跳靴2.6.3
1.过滤器SqlInjectFilter
SqlInjectFilter,实现javax.servlet.Filter接口。即在执行过滤方法中实现具体逻辑。
@Slf4jpublic类SqlInjectFilter实现filter { private static final String SQL _ REG _ EXP= .*( b(select insert into update delete from where and or trans cate drop execute like grant use union order by) b).*;@ Override public void do筛选器(servlet请求servlet请求,ServletResponse servletResponse,FilterChain filterChain)抛出IOException,servlet exception { http servlet request request=(http servlet request)servlet请求;CustomRequestWrapper请求包装器=新的CustomRequestWrapper(请求);MapString,对象参数map=new HashMap();参数映射=getParameterMap(参数映射,请求,请求包装器);//正则校验是否有结构化查询语言关键字for(对象obj :参数映射。entry set()){ Map .Entry entry=(Map .entry)obj;对象值=条目。getvalue();如果(值!=null){ boolean有效=issql注入(值。tostring()、servlet响应);如果(!是有效的){ return} } }过滤链。do过滤器(请求包装器、servlet响应);} private MapString,Object getparameter map(MapString,Object paramMap,HttpServletRequest request,CustomRequestWrapper请求包装器){//1 .邮政请求获取参数if (POST ).equals(request.getMethod().toupper case())){ String body=请求包装器。get body();param map=JSON对象。解析对象(body,hashmap。类);} else { MapString,String[]参数map=请求包装器。getparameter map();//普通的得到请求if (parameterMap!=空参数映射。size()0){设置地图.EntryString,String[]entries=参数映射。条目集();对于(图EntryString,String[]下:个条目){
paramMap.put(next.getKey(), next.getValue()[0]); } } else { //GET请求,参数在URL路径型式,比如server/{var1}/{var2} String afterDecodeUrl = null; try { //编码过URL需解码解码还原字符 afterDecodeUrl = URLDecoder.decode(request.getRequestURI(), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } paramMap.put("pathVar", afterDecodeUrl); } } return paramMap; } private boolean isSqlInject(String value, ServletResponse servletResponse) throws IOException { if (null != value && value.toLowerCase().matches(SQL_REG_EXP)) { log.info("入参中有非法字符: " + value); HttpServletResponse response = (HttpServletResponse) servletResponse; Map<String, String> responseMap = new HashMap<>(); // 匹配到非法字符,立即返回 responseMap.put("code", "999"); responseMap.put("message","入参中有非法字符"); response.setContentType("application/json;charset=UTF-8"); response.setStatus(HttpStatus.OK.value()); response.getWriter().write(JSON.toJSONString(responseMap)); response.getWriter().flush(); response.getWriter().close(); return false; } return true; }}
2.请求装饰类CustomRequestWrapper
在拦截请求时,会读取HttpServletRequest的InputStream,而这种数据流一旦读取后,就没了。那么直接把请求放入过滤器链,后续的环节就读取不到数据了。因此,需要一个装饰类,读取了InputStream数据后,还得回写到请求中。然后把数据完整的装饰类放入过滤器链。这样拦截了请求,读取了数据,并回写了数据,数据完整性得到保证。
public class CustomRequestWrapper extends HttpServletRequestWrapper { private final String body; public CustomRequestWrapper(HttpServletRequest request) throws IOException { super(request); StringBuilder sb = new StringBuilder(); BufferedReader bufferedReader = null; try { InputStream inputStream = request.getInputStream(); if (inputStream != null) { bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); char[] charBuffer = new char[512]; int bytesRead = -1; while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { sb.append(charBuffer, 0, bytesRead); } } else { sb.append(""); } } catch (IOException e) { e.printStackTrace(); throw e; } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); throw e; } } } body = sb.toString(); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes("UTF-8")); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() { return bais.read(); } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream(), StandardCharsets.UTF_8)); } public String getBody() { return this.body; } @Override public String getParameter(String name) { return super.getParameter(name); } @Override public Map<String, String[]> getParameterMap() { return super.getParameterMap(); } @Override public Enumeration<String> getParameterNames() { return super.getParameterNames(); } @Override public String[] getParameterValues(String name) { return super.getParameterValues(name); }}
3.过滤器注册
过滤器生效,需注册。
@Configurationpublic class FilterConfiguration { @Bean("sqlFilter") public SqlInjectFilter sqlInjectFilter() { return new SqlInjectFilter(); } @Bean public FilterRegistrationBean<SqlInjectFilter> sqlFilterRegistrationBean() { FilterRegistrationBean<SqlInjectFilter> filterReg = new FilterRegistrationBean<>(); filterReg.setFilter(sqlInjectFilter()); filterReg.addUrlPatterns("/*"); filterReg.setOrder(1); return filterReg; }}
4.测试辅助类
4.1 结果对象ResultObj
Restful请求返回格式统一。
@Data@NoArgsConstructor@AllArgsConstructor@Builderpublic class ResultObj { private String code; private String message;}
4.2 Restful的Controller类
SqlInjectionController,包括POST请求和GET请求测试。
@RestController@Slf4j@RequestMapping("/inject")public class SqlInjectionController { @PostMapping("/f1") public Object f1(@RequestBody Object obj) { log.info("SqlInjectionController->f1,接收参数,obj = " + obj.toString()); log.info("SqlInjectionController->f1,返回."); return ResultObj.builder().code("200").message("成功").build(); } @GetMapping("/f2") public Object f2(@RequestParam(name = "var") String var) { log.info("SqlInjectionController->f2,接收参数,var = " + var); log.info("SqlInjectionController->f2,返回."); return ResultObj.builder().code("200").message("成功").build(); } @GetMapping("/f3/{var}") public Object f3(@PathVariable("var") String var) { log.info("SqlInjectionController->f3,接收参数,var = " + var); log.info("SqlInjectionController->f3,返回."); return ResultObj.builder().code("200").message("成功").build(); }}
5.测试
5.1 POST请求测试
URL: http://127.0.0.1:18081/server/inject/f1
入参:
{ "userName": "Hangzhou select", "password": "202206112219"}
返回:
{ "code": "999", "message": "入参中有非法字符"}
5.2 GET请求测试1
URL: http://127.0.0.1:18081/server/inject/f2?var=56622 INSert
返回:
{ "code": "999", "message": "入参中有非法字符"}
5.3 GET请求测试2
URL: http://127.0.0.1:18081/server/inject/f3/123 delete
返回:
{ "code": "999", "message": "入参中有非法字符"}
到此这篇关于Springboot详解如何实现SQL注入过滤器过程的文章就介绍到这了,更多相关Springboot SQL注入过滤器内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。