Spring-Cloud-Gateway-实现XSS、SQL注入拦截

XSS和SQL注入是Web应用中常见计算机安全漏洞,文章主要分享通过Spring Cloud Gateway 全局过滤器对XSS和SQL注入进行安全防范。
写这篇文章也是因为项目在经过安全组进行安全巡检时发现项目存储该漏洞后进行系统整改,本文的运行结果是经过安全组验证通过。

使用版本

  • spring-cloud-dependencies Hoxton.SR7
  • spring-boot-dependencies 2.2.9.RELEASE
  • spring-cloud-gateway 2.2.4.RELEASE

核心技术点

1. AddRequestParameterGatewayFilterFactory 获取get请求参数并添加参数然后重构get请求

public GatewayFilter apply(NameValueConfig config) {
    return new GatewayFilter() {
      public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI uri = exchange.getRequest().getURI();
        StringBuilder query = new StringBuilder();
        //获取请求url携带的参数,?号后面参数体,类似cl=3&tn=baidutop10&fr=top1000&wd=31 
        String originalQuery = uri.getRawQuery();
        if (StringUtils.hasText(originalQuery)) {
          query.append(originalQuery);
          if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
            query.append('&');
          }
        }

        String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
        query.append(config.getName());
        query.append('=');
        query.append(value);

        try {
          //重构请求uri
          URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query.toString()).build(true).toUri();
          ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
          return chain.filter(exchange.mutate().request(request).build());
        } catch (RuntimeException var9) {
          throw new IllegalStateException("Invalid URI query: \"" + query.toString() + "\"");
        }
      }

      public String toString() {
        return GatewayToStringStyler.filterToStringCreator(AddRequestParameterGatewayFilterFactory.this).append(config.getName(), config.getValue()).toString();
      }
    };
  }

2. [Spring Cloud Gateway中RequestBody只能获取一次的问题解决方案](https://blog.youkuaiyun.com/dear_little_bear/article/details/105319657)
3. Spring Gateway GlobalFilter

技术实现

  1. 创建Filter 实现GlobalFilter, Ordered
@Slf4j
@Component
public class SqLinjectionFilter implements GlobalFilter, Ordered {

  @SneakyThrows
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
    // grab configuration from Config object
    log.debug("----自定义防XSS攻击网关全局过滤器生效----");
    ServerHttpRequest serverHttpRequest = exchange.getRequest();
    HttpMethod method = serverHttpRequest.getMethod();
    String contentType = serverHttpRequest.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
    URI uri = exchange.getRequest().getURI();

    Boolean postFlag = (method == HttpMethod.POST || method == HttpMethod.PUT) &&
        (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType) || MediaType.APPLICATION_JSON_VALUE.equals(contentType));

    //过滤get请求
    if (method == HttpMethod.GET) {

      String rawQuery = uri.getRawQuery();
      if (StringUtils.isBlank(rawQuery)){
        return chain.filter(exchange);
      }

      log.debug("原请求参数为:{}", rawQuery);
      // 执行XSS清理
      rawQuery = XssCleanRuleUtils.xssGetClean(rawQuery);
      log.debug("修改后参数为:{}", rawQuery);

      //	如果存在sql注入,直接拦截请求
      if (rawQuery.contains("forbid")) {
        log.error("请求【" + uri.getRawPath() + uri.getRawQuery() + "】参数中包含不允许sql的关键词, 请求拒绝");
        return setUnauthorizedResponse(exchange);
      }

      try {
        //重新构造get request
        URI newUri = UriComponentsBuilder.fromUri(uri)
            .replaceQuery(rawQuery)
            .build(true)
            .toUri();

        ServerHttpRequest request = exchange.getRequest().mutate()
            .uri(newUri).build();
        return chain.filter(exchange.mutate().request(request).build());
      } catch (Exception e) {
        log.error("get请求清理xss攻击异常", e);
        throw new IllegalStateException("Invalid URI query: \"" + rawQuery + "\"");
      }
    }
    //post请求时,如果是文件上传之类的请求,不修改请求消息体
    else if (postFlag){

      return DataBufferUtils.join(serverHttpRequest.getBody()).flatMap(d -> Mon
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值