배경
새로운 프로젝트에서 화이트리스트 IP 검증 로직(IP 기반 접근 제한)을 구현하게 되었다. 처음에는 단순하게 request.getRemoteAddr()를 사용하면 될 줄 알았는데, 실제 운영 환경에서는 중간에 프록시를 거치다보니 실제 클라이언트 IP가 아닌 프록시 IP가 조회되는 문제가 있었다. 이 문제를 해결하기 위해 알게된 X-Forwarded-For와 X-Real-IP에 대해 알아보자
문제 상황
웹 애플리케이션을 개발하다 보면 클라이언트의 실제 IP 주소가 필요한 경우가 많다. 특히 보안 정책, 접근 제어, 로깅 및 분석 등의 목적으로 사용된다. 하지만 실제 운영을 위한 웹 아키텍처에서는 클라이언트와 서버 사이에 다양한 중간 계층들이 존재한다. 로드 밸런서, 리버스 프록시, CDN 등을 거치면서 서버가 실제로 받는 IP는 클라이언트의 실제 IP 주소가 아닌 바로 직전의 프록시 IP 주소가 된다.
현재 내가 담당한 프로젝트의 아키텍처는 다음과 같다.
Client -> Load Balancer -> Reverse Proxy -> WAS
이런 구조에서 request.getRemoteAddr()를 사용하면 실제 클라이언트 IP가 아닌 바로 직전 프록시의 IP를 반환한다.
화이트리스트 검증에서는 실제 클라이언트의 IP가 필요하기 때문에 이 문제를 해결해야 했다.
X-Forwarded-For (XFF) 헤더
X-Forwarded-For 헤더는 HTTP 프록시나 로드 밸런서를 통해 접속하는 클라이언트의 원 IP 주소를 식별하는 사실상의 표준 헤더이다. 클라이언트와 서버 중간에서 중간 계층을 거치면서 IP가 변경되는데, 클라이언트의 원 IP 주소를 보기 위해서 X-Forwarded-For 요청 헤더가 사용된다.
동작 방식
X-Forwarded-For: <client>, <proxy1>, <proxy2>
각 프록시를 거칠 때마다 우측 끝에 IP를 추가한다.
User(1.1.1.1)
└ Proxy(2.2.2.2) - X-Forwarded-For: 1.1.1.1
└ Nginx(3.3.3.3) - X-Forwarded-For: 1.1.1.1, 2.2.2.2
가장 왼쪽 IP가 최초 클라이언트의 IP이고, 가장 오른쪽 IP가 마지막 프록시의 IP이다.
X-Real-IP 헤더
X-Real-IP는 바로 직전 클라이언트의 IP를 나타낸다. XFF와 달리 단일 IP 값만을 전달한다.
User - Nginx - Tomcat # X-Real-IP는 User IP
User - Proxy - Nginx - Tomcat # X-Real-IP는 Proxy IP
보안 고려사항
XFF와 X-Real-IP 헤더의 문제점은 클라이언트가 조작할 수 있다는 것이다. 악의적인 사용자가 가짜 IP를 헤더에 추가해서 보안 정책을 우회할 수 있는 문제가 있다. 그래서 신뢰할 수 있는 리버스 프록시를 통해서만 접근을 허용하고, 다른 경로로 백엔드 서버로의 직접 접근을 차단해야 한다.
참조
What is X-Forwarded-For and when can you trust it?
The X-Forwarded-For (XFF) HTTP header provides crucial insight into the origin of web requests. The header works as a mechanism for conveying the original...
httptoolkit.com
X-Forwarded-For - HTTP | MDN
X-Forwarded-For (XFF) 헤더는 HTTP 프록시나 로드 밸런서를 통해 웹 서버에 접속하는 클라이언트의 원 IP 주소를 식별하는 사실상의 표준 헤더다. 클라이언트와 서버 중간에서 트래픽이 프록시나 로드
developer.mozilla.org
'Network' 카테고리의 다른 글
| Backend - RESTful하게 API 설계하는 방법 (6) | 2024.11.12 |
|---|---|
| HTTP - 헤더 정보 (0) | 2023.08.01 |
| HTTP - 알아두면 좋은 URI 설계 개념 (0) | 2023.08.01 |
| HTTP - HTTP 메서드 (0) | 2023.07.20 |
| HTTP - HTTP 기본 메시지 (0) | 2023.07.20 |