我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Springboot详解如何实现SQL注入过滤器过程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Springboot详解如何实现SQL注入过滤器过程

场景:以过滤器(Filter)的方式,对所有http请求的入参拦截,使用正则表达式匹配入参中的字符串。存在SQL注入风险的参数,中断请求,并立即返回提示信息。不存在SQL注入风险的参数,校验通过后,放入过滤器链,继续后续业务。

环境:本例是基于springboot的web工程,版本:springboot 2.6.3

1.过滤器SqlInjectFilter

SqlInjectFilter,实现javax.servlet.Filter接口。即在doFilter方法中实现具体逻辑。

@Slf4j
public class SqlInjectFilter implements Filter {
  private static final String SQL_REG_EXP = ".*(\\b(select|insert|into|update|delete|from|where|and|or|trancate" +
      "|drop|execute|like|grant|use|union|order|by)\\b).*";
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    CustomRequestWrapper requestWrapper = new CustomRequestWrapper(request);
    Map<String, Object> parameterMap = new HashMap<>();
    parameterMap =getParameterMap(parameterMap, request, requestWrapper);
    // 正则校验是否有SQL关键字
    for (Object obj : parameterMap.entrySet()) {
        Map.Entry entry = (Map.Entry) obj;
        Object value = entry.getValue();
        if (value != null) {
            boolean isValid = isSqlInject(value.toString(), servletResponse);
            if (!isValid) {
                return;
            }
        }
    }
    filterChain.doFilter(requestWrapper, servletResponse);
  }
  private Map<String, Object> getParameterMap(Map<String, Object> paramMap, HttpServletRequest request, CustomRequestWrapper requestWrapper) {
    // 1.POST请求获取参数
    if ("POST".equals(request.getMethod().toUpperCase())) {
        String body = requestWrapper.getBody();
        paramMap = JSONObject.parseObject(body, HashMap.class);
    } else {
        Map<String, String[]> parameterMap = requestWrapper.getParameterMap();
        //普通的GET请求
        if (parameterMap != null && parameterMap.size() > 0) {
            Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
            for (Map.Entry<String, String[]> next : entries) {
                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.过滤器注册

过滤器生效,需注册。

@Configuration
public 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
@Builder
public 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注入过滤器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Springboot详解如何实现SQL注入过滤器过程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot过滤器实现项目内接口过滤详解

这篇文章主要为大家详细介绍了SpringBoot如何利用过滤器实现项目内接口过滤,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
2023-05-16

SQL实现数据过滤流程详解

目录数据准备student 表过滤数据过滤单个值过滤null 值过滤集合BETWEEN IN NOT IN使用通配符过滤数据LIKE使用逻辑操作符组合WHERE子句数据准备student 表CREATE TABLE `student` (
2023-01-05

SpringBoot+Redis如何实现布隆过滤器

小编给大家分享一下SpringBoot+Redis如何实现布隆过滤器,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!简述关于布隆过滤器的详细介绍,我在这里就不再赘述一遍了我们首先知道:BloomFilter使用长度为m bi
2023-06-29

SpringBoot配置拦截器实现过程详解

在系统中经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中,即平时所说的"权限检测"及"日志记录",下面这篇文章主要给大家介绍了关于在SpringBoot项目中整合拦截器的相关资料,需要的朋友可以参考下
2022-11-13

使用SpringBoot如何实现自定义过滤器与拦截器

使用SpringBoot如何实现定义过滤器与拦截器?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、自定义过滤器创建一个过滤器,实现javax.servlet.Filter
2023-05-31

Nest.js之依赖注入原理及实现过程详解

这篇文章主要为大家介绍了Nest.js之依赖注入原理及实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-12

SpringBoot开发存储服务器实现过程详解

这篇文章主要为大家介绍了SpringBoot开发存储服务器实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-08

Java微服务Filter过滤器集成Sentinel实现网关限流过程详解

这篇文章主要介绍了Java微服务Filter过滤器集成Sentinel实现网关限流过程,首先Sentinel规则的存储默认是存储在内存的,应用重启之后规则会丢失。因此我们通过配置中心Nacos保存规则,然后通过定时拉取Nacos数据来获取规则配置,可以做到动态实时的刷新规则
2023-02-10

SpringBoot配置自定义拦截器实现过程详解

在系统中经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中,即平时所说的"权限检测"及"日志记录",下面这篇文章主要给大家介绍了关于在SpringBoot项目中整合拦截器的相关资料,需要的朋友可以参考下
2022-11-13

SpringBoot如何通过自定义注解实现参数校验

今天小编给大家分享一下SpringBoot如何通过自定义注解实现参数校验的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.
2023-07-04

SpringBoot使用自定义注解实现数据脱敏过程详细解析

这篇文章主要介绍了SpringBoot自定义注解之脱敏注解详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-15

SpringBoot基于过滤器和内存如何实现重复请求拦截功能

这篇文章主要介绍了SpringBoot基于过滤器和内存如何实现重复请求拦截功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot基于过滤器和内存如何实现重复请求拦截功能文章都会有所收获,下面我们
2023-07-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录