본문 바로가기
IT/JAVA&SpringBoot

Spring 서비스에서 getRemoteAddr()로 IP가 정상 추출되지 않을 때 조치 방법

by twofootdog 2026. 3. 13.
반응형

안녕하세요

레거시 프로젝트를 진행하다 보면 Spring 서비스를 Tomcat WAS에 올려서 구동하는 경우가 있는데요

이때 애플리케이션에서는 유입된 클라이언트 IP를 추출하기 위해(IP 허용여부 체크 등을 위해) request.getRemoteAddr() 메소드를 주로 사용합니다

과거 레거시 애플리케이션이 적용된 아키텍쳐에서는 getRemoteAddr() 메소드가 클라이언트 IP를 정상 채번하지만, 만약 Tomcat 이전에 ALB나 WAF 등이 적용이 될 경우 getRemoteAddr() 메소드를 사용하면 클라이언트 IP가 아닌 Tomcat을 호출한 직전의 IP(ALB 나 WAF 등 Proxy IP)를 추출하게 됩니다.

때문에 호출한 직전의 IP가 아닌, 클라이언트 IP를 추출하게 하기 위해서는 다음과 같은 조치가 필요합니다(JDK 1.8, 톰캣 8.5 버전으로 작성했습니다)

 


1. Tomcat 설정에 RemoteIpValve 추가

가장 좋은 방법은 Tomcat 설정을 변경하는 방법입니다.

우선 ALB나 WAF에서 XFF(x-forwarded-for) 헤더 기능 활성화가 필요합니다.

그 다음 애플리케이션에서는 Tomcat 설정파일(server.xml)RemoteIpValve 설정을 추가해주고 remoteIpHeader를 "x-forwarded-for," internalProxies에 클라이언트 IP 이외에 IP들(Proxy, WAF 등)의 IP 대역을 넣어주면 됩니다.

이렇게 적용하면 InternalProxies에 있는 IP 대역은 "내부 Proxy IP 이구나" 라고 하고 XFF 헤더에서 삭제(filtering) 해주고 결국 클라이언트 IP만 남아서 전달됩니다. 

server.xml : 

<Valve className="org.apache.catalina.valves.RemoteIpValve"
       internalProxies="10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|127\.0\.0\.1"
       remoteIpHeader="x-forwarded-for"
       proxiesHeader="x-forwarded-by"
       protocolHeader="x-forwarded-proto" />

 


2. 어플리케이션 소스 변경

두번째 방법은 애플리케이션 소스를 변경하는 방법입니다.

이 방법도 첫번째와 마찬가지로 ALB나 WAF에서 XFF(x-forwarded-for) 헤더 기능 활성화가 필요합니다.

그리고 어플리케이션(스프링) 소스에 아래 내용을 추가해주면 됩니다(HttpServletRequestWrapper를 상속 받아서 getRemoteAddr() 메소드를 오버라이딩해서 XFF 헤더의 첫번째 IP를 추출하도록 수정해주면 됩니다)

그 다음 필터에 해당 Wrapper를 추가해주면 됩니다.

RequestWrapper.java / RequestWrappingFilter : 

public RequestWrapper extends HttpServletRequestWrapper {

    public RequestWrapper(HttpServletRequest request) {
            super(request);
        }
	...

    @Override
    public String getRemoteAddr() {
        String xff = super.getHeader("X-Forwarded-For");
        if (xff != null && !xff.trim().isEmpty()) {
            return xff.split(",")[0].trim();
        }
    }
}

 

@Component
public class RequestWrappingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        if (request instanceof HttpServletRequest) {
            // 원본 Request를 새로 만든 Wrapper로 감싸서 다음 필터로 넘김
            RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request);
            chain.doFilter(requestWrapper, response);
        } else {
            chain.doFilter(request, response);
        }
    }
}

 

 

3. 그 외(스프링부트 사용 시)

스프링부트 사용 시에는 좀 더 방법이 단순합니다. application.yml 아래 설정만 추가해주면 됩니다.

application.yml : 

server:
  forward-headers-strategy: native  # 스프링이 내부적으로 RemoteIpValve를 활성화

 

 

 

 

반응형

댓글