이번에 일하면서 자동화 공격(쉽게 생각해서 DDOS 공격)을 방어할 일이 생겼습니다.
이에 대한 조치를 어떻게 하면 좋을지 고민하다가,
Rate Limiter 라는 개념을 알게 되었고,
Tomcat 자체에서 해당 Limiter 를 제공한다는 점을 알아내서 이를 반영하게 되었습니다.
그 방법을 공유합니다.
참고로 spring legacy 프로젝트( = spring boot 를 사용하지 않는 환경 ) 이다 보니
web.xml 등을 직접 작성하는 것이 좀 보일 겁니다.spring boot 의 경우에는
maven dependency 추가
작업은 패스해도 됩니다.
tomcat-embedded 라이브러리에 이미 필요한 클래스가 내장되어 있습니다.
당연하지만web.xml
설정도 패스해도 됩니다.
{tomcat-home}/bin/catalina.jar
를 압축해제해서 확인해보면 아래와물론 톰캣 실행시 자동으로 클래스가 추가되지만, 개발 시에도 해당 클래스의
정보를 참조해야 되는 경우가 많습니다. 그러므로 아래처럼 maven dependency 를 추가 해줍시다.
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-catalina -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.85</version><!-- 자신의 톰캣 버전과 일치시킨다. -->
<scope>provided</scope><!-- 톰캣 컨테이너가 어짜피 제공하니 provided! -->
</dependency>
<!-- 원격 IP 를 추출하여, request.remoteAddr 에 설정한다. -->
<filter>
<filter-name>RemoteIpFilter</filter-name>
<filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RemoteIpFilter</filter-name>
<url-pattern>/remoteApi/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<!-- RATE LIMITER -->
<filter>
<filter-name>CustomRateLimiterFilter</filter-name>
<filter-class>me.dailycode.web.filter.CustomRateLimiterFilter</filter-class>
<init-param>
<param-name>bucketDuration</param-name>
<param-value>5</param-value>
</init-param>
<init-param>
<param-name>bucketRequests</param-name>
<param-value>2</param-value>
</init-param>
</filter>
<!--
위에 설정한 init-param 값들이 궁금하다면
https://tomcat.apache.org/tomcat-9.0-doc/config/filter.html#Rate_Limit_Filter
를 참조하길 바란다.
-->
<filter-mapping>
<filter-name>CustomRateLimiterFilter</filter-name>
<url-pattern>/remoteApi/*</url-pattern>
</filter-mapping>
굳이 Custom 하게 만든 이유는 HTTP METHOD 중에서 POST, PUT, DELETE 만 잡고 싶어서
그런 겁니다. RateLimitFilter 자체로는 그런 필터링 작업이 없어서 이렇게 했습니다.
package me.dailycode.web.filter;
import org.apache.catalina.filters.RateLimitFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* org.apache.catalina.filters.RateLimitFilter 의 내용을 뱃겨왔다.<br>
*/
public class CustomRateLimiterFilter extends RateLimitFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String method = httpRequest.getMethod();
// POST, PUT, DELETE 는 모두 RateLimit 대상이다.
// 단! POST Method 중에서도 조회성 Post Http Request 가 있다면 이를 잘 조치해야 한다.
if ("POST".equalsIgnoreCase(method)
|| "PUT".equalsIgnoreCase(method)
|| "DELETE".equalsIgnoreCase(method)) {
super.doFilter(request, response, chain);
return;
}
}
chain.doFilter(request, response);
}
}
개인적으로 https://tomcat.apache.org/tomcat-9.0-doc/config/filter.html
에서 제공하는 필터들을 가볍게 한번 쭉 둘러보는 것도 좋다고 생각합니다.