Spring Cloud Zuul防DDOS攻击

  前一段时间,公司的短信服务经常收到预警,当时初步猜测我们的短信服务受到了攻击,于是想到了两种实现方案。

  方案一:

    采用nginx防止DDOS(网上有很多案例可以借鉴)

  方案二:

   采用Spring Cloud Zuul(网关)层实现防DDOS

 

 

  因考虑如果使用nginx层进行防DDOS拦截,会导致线上的其他服务受到影响,并且使用nginx拦截无法像Zuul网关那么容易可以自定义修改,所以果断采取方案二,以下是代码片段:

步骤1:获取请求路径(单独对短信发送接口进行拦截),也可最避免其他接口受到影响

HttpServletRequest request = context.getRequest();
// 获取请求路径
String uri = request.getRequestURI();

if (uri != null && uri.contains("sendSms***")){
    // 获取请求IP
    String reqIpAddress = HttpReqIPUtil.getHttpClientIP(request);

}

步骤2:采用redis进行IP请求判断,达到异常IP封禁的效果

  一般而言人在一秒内,请求频次最多大概在3-4下,通过设置ip的失效时间判断1秒内超过5次,将拉入黑名单

String blockIp = this.redisService.get(String.class , reqIpAddress);
if (StringUtils.isNotEmpty(blockIp){
    RequestContext context = RequestContext.getCurrentContext();
    //终止转发,返回响应报文
    context.setSendZuulResponse(false); 
    context.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
    return;
}
// 限制用户一秒内的请求次数(rdsReqKey 为你自定义的key)
Long reqNum = redisService.incr(rdsReqKey);
// 失效时间(需判断失效时间,因原子性问题可能导致redis未设置失效时间)
Long ttl = redisService.ttl(rdsReqKey);
if (reqNum.longValue() == BigDecimal.ONE.longValue() || ttl < 0){
    redisService.expire(rdsReqKey , validTime);
}
// 加入失效时间判断(-1表示永久有效,需要排除永久有效的key避免误杀)
// reqNum 为1秒内请求的次数
if (reqNum >= 5 && ttl > -1){
    log.error("IP:{},mobile:{}, 请求超过:{},被拉黑名单" , reqIpAddress , mobile, reqNum);
    this.redisService.set(reqIpAddress, reqIpAddress);
    // 设置ip的禁用时间
    this.redisService.expire(reqIpAddress, blacklistExptime);
}




Zuul代码片段

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 描述:
 * 短信
 *
 * @author 34861
 * @create 2019-04-18 11:40
 */
@Component
@Slf4j
public class SmsFilter extends ZuulFilter {

   

    @Autowired
    private RedisService redisService;
    /**
     *  Filter类型
     *  
  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。 *
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。 *
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。 *
  • ERROR:在其他阶段发生错误时执行该过滤器。 */ @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { //获取当前请求上下文,在这个上下文基础上可以做很多事情了。具体自己查看API。 RequestContext context = RequestContext.getCurrentContext(); //获取原始Htpp请求,有这个对象也可以做很多事情了。自己发挥吧。 HttpServletRequest request = context.getRequest(); HttpServletResponse response = context.getResponse(); this.verifyBlockList(context ,request); return null; } }
  • 以上代码仅为代码片段,可根据具体业务实现

     

    你可能感兴趣的:(java,spring,cloud)