헤어비 서비스를 운영하며 종종 위와 같은 exception이 발생하였다. 서비스에서 허용하지 않은 HTTP method와 URL에 잠재적으로 악의적인 문자열 "%2e"가 포함되어 이를 거부한다는 메세지인데, 이는 스프링 시큐리티에서 제공하는 기능 중 하나이다.
서비스에 악의적인 요청으로 인해 해당 exception을 발생시키는 것임은 알았지만, 왜 해당 문자열을 거부하는 것이고 어떻게 스프링 시큐리티의 어떤 기능으로 이를 방지한 것인지 좀더 자세히 알아보고자 한다.
Spring Security의 HttpFirewall은 웹 애플리케이션을 보호하기 위한 필터로, 잠재적으로 악의적인 요청을 차단한다. 필자의 경우 아래의 상황때문에 필터가 작동하였다.
1. 악의적인 문자열 포함
URL 인코딩된 문자열 %2e는 마침표(.)를 의미한다. 마침표는 파일 시스템 경로에서 상위 디렉토리를 참조할 때 사용될 수 있다. 예를 들어, ../와 같이 사용하면 상위 디렉토리로 이동할 수 있다. 만약 서버가 이러한 요청을 제대로 처리하지 못하면, 공격자는 서버의 중요한 파일에 접근할 수 있다. %2e와 같은 URL 인코딩된 문자열은 이런 공격을 우회하기 위해 사용될 수 있기 때문에, 기본적으로 차단된다.
이러한 공격을 디렉토리 트래버셜(Directory Traversal) 공격이라고 한다.
2. 허용되지 않은 HTTP 메서드
HTTP 메서드는 웹 애플리케이션과 상호작용하는 방법을 정의한다. Spring Security는 기본적으로 일부 메서드를 허용하지 않는다. 그 이유는 이 메서드들이 특정한 보안 취약점을 유발할 수 있기 때문이다.
PURGE 메서드
PURGE 메서드는 주로 캐시 서버에서 특정 항목을 제거하는 데 사용된다. 일반적인 웹 애플리케이션에서 잘 사용되지 않으며, 만약 허용된다면 캐시 일관성을 해칠 수 있다.
TRACE 메서드
TRACE 메서드는 요청이 서버에 도달할 때까지의 경로를 추적하는 데 사용된다. 이는 디버깅에 유용할 수 있지만, 클라이언트가 요청에 포함된 헤더 정보를 확인할 수 있게 한다. 이는 XSS(Cross-Site Scripting) 공격을 유발할 수 있기 때문에 보안상의 이유로 차단된다.
시큐리티의 기본 구현체인 StrictHttpFirewall 에서는, 악성 URL로 인한 사이드 이펙트를 최소화하기 위해 위와 같은 수많은 문자들이 포함된 URL은 아예 거부하고 있다.
이미지를 보면 필자가 경험한 "%2e"을 거부하는 것을 알 수 있다.
만약 %2e와 같은 마침표를 허용하고 싶다면 아래와 같은 방법을 사용할 수 있다.
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public HttpFirewall customHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedPeriod(true); // URL 인코딩된 마침표 허용
return firewall;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpFirewall(customHttpFirewall());
}
}
이 설정을 통해 URL 인코딩된 마침표를 허용하여 RequestRejectedException 예외를 방지할 수 있다.
HTTP Method 커스텀은?
Spring은 아래의 코드처럼 허용한 Method의 요청을 받기 때문에 커스텀을 통해 HttpFirewall을 수정하더라도 HTTP Method가 일치하지 않는다면 405 Error를 호출한다.
@GetMapping("/test")
public Response<TestResponse> test() {
Response.success(testService.test());
}
공식문서
https://docs.spring.io/spring-security/reference/servlet/exploits/firewall.html