预防Dos攻击

Dos----拒绝服务攻击,一般是构造特殊的输入,使得后台的处理耗时远超正常水平,随着请求越来越多,后台服务越发疲于奔命,最后因资源耗尽,无法再接受新的请求,最终造成拒绝服务的效果。

特殊输入例如:
分页查询时传一个很大的pageSize;
入参是一个很大的集合。

对于前者,做一个公共函数检查pageSize的大小,确定合理的范围即可。
对于后者,往往是在post请求里,可以做一个filter来处理所有的incoming request。参考了一些资料,样例代码如下:

@Component
public class BodySizeLimitFilter implements Filter {

    private static final List<String> METHODS_WITH_BODY = Collections.unmodifiableList(
        Arrays.asList("POST", "PUT", "OPTIONS", "DELETE", "PATCH"));

    private static final String CONTENT_LENGTH_HEADER = "Content-Length";

    private static final int TOO_LARGE_STATUS = 413;

    @Value("${reqbody.maxsize:4096}")
    private long contentLengthLimit;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        if (!METHODS_WITH_BODY.contains(httpServletRequest.getMethod())) {
            chain.doFilter(httpServletRequest, httpResponse);
            return;
        }

        long contentSize = getContentLength(httpServletRequest);

        if (contentSize > contentLengthLimit) {
            resetRespAndSetStatus(httpResponse, TOO_LARGE_STATUS);
        } else {
            chain.doFilter(request, response);
        }
    }

    private void resetRespAndSetStatus(HttpServletResponse response, int status) {
        response.reset();
        response.setStatus(status);
    }

    private long getContentLength(HttpServletRequest httpRequest) {
        String contentLength = httpRequest.getHeader(CONTENT_LENGTH_HEADER);
        return safeToLong(contentLength, 0);
    }
}

不过,考虑到content-length也是可以被篡改的,还是要在rest入口处做一下集合长度的校验。这里可使用springboot的@Valid注解。
对于前端POST调用传过来的requestBody参数,在函数声明里用jaxrs规范的@Valid注解处理,比如:

@Path("/test")
@Consumes({ "application/json;charset=UTF-8" })
@Named
public class TestRestService {

    @POST
    @Path("/hello")
    @Consumes({ "application/json" })
    @Produces({ "application/json" })
    public ServiceResponse<String> test(@Valid TestParam testParam) {
        throw new BaseException("i18n.test.example");
    }

同时,在TestParam数据类里用@Size等注解标记要校验的字段:

@Data
public class TestParam {
    @Size(max = 10, min = 2, message = "[strs]size between 2~10")
    private List<String> strs;

    @Size(max = 6, min = 1, message = "[singleStr]length between 1~6")
    private String singleStr;

    @Min(value = 0)
    @Max(value = 1)
    private int num;
}

这样spring框架就会自动为我们检查TestParam成员中list类型的长度、整型的大小、字符串类型的长度等。一旦有错误,就会抛出ConstraintViolationException异常,我们设法截获该异常,将错误信息填到Response中,给前台展示。
顺带说一下,校验时,spring controller类上的@Validated注解其实可以不要的。若调用内部spring bean时需做参数校验,则必须在spring bean的类定义上加@Validated注解(@Valid注解不能用于类),然后再在要校验的方法参数前加@Valid等注解。
对于GET调用的参数,校验起来更为简单,直接用@Size等注解修饰函数参数即可:

    @GET
    @Path("/helloPrimitive")
    @Consumes({ "application/json" })
    @Produces({ "application/json" })
    public ServiceResponse<String> testPrimitive(@QueryParam("id") @Max(value = 10) int id,
        @QueryParam("desc") @Size(max=15) String desc) {
        throw new BaseException("i18n.test.example");
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值