Tomcat 에서 자동화 공격을 어떻게 방어할까?

식빵·2024년 3월 20일
0

Spring Lab

목록 보기
30/34
post-thumbnail

이번에 일하면서 자동화 공격(쉽게 생각해서 DDOS 공격)을 방어할 일이 생겼습니다.

이에 대한 조치를 어떻게 하면 좋을지 고민하다가,
Rate Limiter 라는 개념을 알게 되었고,
Tomcat 자체에서 해당 Limiter 를 제공한다는 점을 알아내서 이를 반영하게 되었습니다.

그 방법을 공유합니다.

참고로 spring legacy 프로젝트( = spring boot 를 사용하지 않는 환경 ) 이다 보니
web.xml 등을 직접 작성하는 것이 좀 보일 겁니다.

spring boot 의 경우에는 maven dependency 추가 작업은 패스해도 됩니다.
tomcat-embedded 라이브러리에 이미 필요한 클래스가 내장되어 있습니다.
당연하지만 web.xml 설정도 패스해도 됩니다.


실제 라이브러리 경로

  • {tomcat-home}/bin/catalina.jar 를 압축해제해서 확인해보면 아래와
    같이 RateLimitFilter 클래스가 존재하는 것을 알 수 있다.

  • 톰캣 실행 시에 위에 보이는 모든 클래스들이 클래스 패스에 추가되면서
    웹앱(war) 내부에 jar 가 없더라도 톰캣 제공 클래스들을 사용할 수 있게 됩니다.



maven dependency 추가

물론 톰캣 실행시 자동으로 클래스가 추가되지만, 개발 시에도 해당 클래스의
정보를 참조해야 되는 경우가 많습니다. 그러므로 아래처럼 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>
  • 당연하지만 provided 처리를 해줘야 합니다!



web.xml 설정

<!-- 원격 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 Filter 작성

굳이 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
에서 제공하는 필터들을 가볍게 한번 쭉 둘러보는 것도 좋다고 생각합니다.

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글