클라이언트 ip 가져오기
request.getClientIP()
로컬에선 문제가 없었으나
올리고 나니 문제가 생겼다.
백서버가 2개 있고, 로드밸런서가 있는데..
클라이언트 ip를 응답 데이터에 넣기 위해
request.getClientIP()그대로 썼더니
첨보는 ip가 튀어나온다..
지피티가 로드밸런서나 프록시 ip로 예상된다고 알려준다.
x-forwarded-for 헤더가 안보인다.
request.getHeader("X-Forwarded-For"); 를 로그로 찍어봐도 안나온다.
따라서 설정이 안돼있다고 예상했다.
네, 로드밸런서에 X-Forwarded-For 헤더 추가 설정을 하면, request.getHeader("X-Forwarded-For")로 클라이언트 IP를 제대로 가져올 수 있을 가능성이 높습니다.
현재 상황에서는 로드밸런서가 클라이언트의 IP를 전달하지 않고, 요청을 처리한 로드밸런서의 IP만 서버에 전달하고 있는 것으로 보입니다. 이는 X-Forwarded-For 헤더 설정이 비활성화되어 있기 때문입니다.
1. X-Forwarded-For 헤더가 추가되면 어떻게 동작하나?
- 로드밸런서가 클라이언트의 실제 IP를 X-Forwarded-For 헤더에 추가합니다.
- 서버에서 request.getHeader("X-Forwarded-For")를 호출하면 클라이언트의 IP를 가져올 수 있습니다.
예를 들어:
- 클라이언트 IP가 192.168.1.100이고,
- 로드밸런서가 10.0.0.1이라고 가정하면,
로드밸런서에서 요청을 전달할 때, 다음과 같은 헤더가 추가됩니다:
X-Forwarded-For: 192.168.1.100
서버에서 이를 읽으면, 결과적으로 192.168.1.100이 반환됩니다.
2. 여러 로드밸런서가 있는 경우
만약 로드밸런서가 여러 계층인 경우, X-Forwarded-For 헤더에 추가적인 IP가 붙습니다.
예:
X-Forwarded-For: 192.168.1.100, 10.0.0.1
여기서 **첫 번째 IP(192.168.1.100)**가 클라이언트의 실제 IP입니다.
이를 처리하기 위해 서버에서 헤더 값을 파싱해야 합니다:
String ip = request.getHeader("X-Forwarded-For");
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim(); // 첫 번째 IP 추출
}
3. 로드밸런서에 X-Forwarded-For 헤더 설정 추가
로드밸런서가 클라이언트의 IP를 헤더에 추가하도록 설정해야 합니다. 로드밸런서에 따라 설정 방법이 다릅니다:
(1) AWS ALB/ELB (Elastic Load Balancer):
AWS ALB는 기본적으로 X-Forwarded-For 헤더를 자동으로 추가합니다. 만약 헤더가 보이지 않는다면 ALB의 HTTP 헤더 설정을 확인하세요.
(2) NGINX 로드밸런서:
nginx.conf에 다음을 추가해야 합니다:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
(3) HAProxy:
HAProxy는 기본적으로 X-Forwarded-For 헤더를 지원합니다. 다음과 같은 설정이 필요합니다:
http-request add-header X-Forwarded-For %[src]
4. X-Forwarded-For 없이 처리하는 방법 (임시 해결책)
로드밸런서 설정을 바로 변경하기 어려운 경우, 다른 대안을 고려해야 합니다:
(1) getRemoteAddr() 활용
- 클라이언트와 로드밸런서 간 네트워크 환경을 잘 이해하고, 로드밸런서의 IP를 필터링해서 제외합니다.
- 로드밸런서 뒤에서 직접 request.getRemoteAddr()로 클라이언트 IP를 가져오는 것은 보통 부정확합니다.
(2) 직접 클라이언트로부터 IP를 전달하도록 요청
클라이언트가 자신의 IP를 직접 HTTP 요청의 커스텀 헤더로 추가하도록 설계합니다. 예:
fetch('/api', {
headers: {
'Client-IP': userIpAddress // 클라이언트에서 직접 IP 전달
}
});
서버에서 이를 읽어 사용합니다:
String clientIp = request.getHeader("Client-IP");
주의: 이 방법은 보안상 취약하며, 신뢰할 수 없는 환경에서는 사용하지 않는 것이 좋습니다.
결론
- 로드밸런서 설정에서 X-Forwarded-For 헤더를 추가하는 것이 최선의 방법입니다. 설정만 추가되면, request.getHeader("X-Forwarded-For")를 통해 클라이언트 IP를 안전하게 가져올 수 있습니다.
- 만약 로드밸런서를 수정할 수 없는 상황이라면, 클라이언트가 직접 IP를 전달하도록 설계하거나 임시로 getRemoteAddr()를 사용하세요. 하지만 정확성이나 보안은 다소 떨어질 수 있습니다.
1. X-Forwarded-For가 없을 때
로드밸런서가 클라이언트의 IP 정보를 전달하지 않는 경우:
- 서버는 클라이언트의 IP를 알 수 없고, 대신 요청을 전달한 로드밸런서의 IP만 확인하게 됩니다.
- 이때, request.getRemoteAddr()를 호출하면 로드밸런서의 IP를 반환합니다.
요청 흐름:
- 클라이언트 (192.168.1.100) → 로드밸런서 (10.0.0.1) → 서버 (172.16.0.1)
- 헤더가 없는 상태에서 서버가 요청을 확인하면:
- request.getRemoteAddr() → "10.0.0.1" (로드밸런서의 IP)
2. X-Forwarded-For가 있을 때
로드밸런서가 클라이언트의 실제 IP를 X-Forwarded-For 헤더에 추가하는 경우:
- 서버는 이 헤더를 통해 클라이언트의 실제 IP를 확인할 수 있습니다.
- request.getHeader("X-Forwarded-For")를 호출하면 클라이언트의 IP를 반환합니다.
요청 흐름:
- 클라이언트 (192.168.1.100) → 로드밸런서 (10.0.0.1) → 서버 (172.16.0.1)
- 로드밸런서가 X-Forwarded-For 헤더에 클라이언트 IP를 추가:
- 요청 헤더:
X-Forwarded-For: 192.168.1.100
- 요청 헤더:
- 서버가 요청을 확인하면:
- request.getHeader("X-Forwarded-For") → "192.168.1.100" (클라이언트의 실제 IP)
- request.getRemoteAddr() → "10.0.0.1" (로드밸런서의 IP)
3. 다중 프록시가 있는 경우
로드밸런서 외에 추가적인 프록시 서버가 요청을 전달하는 경우, X-Forwarded-For 헤더에 각 프록시를 거치는 IP가 순서대로 추가됩니다.
요청 흐름:
- 클라이언트 (192.168.1.100) → 프록시1 (172.20.0.1) → 로드밸런서 (10.0.0.1) → 서버 (172.16.0.1)
- 로드밸런서가 요청을 전달하며 X-Forwarded-For 헤더에 클라이언트와 프록시의 IP를 추가:
- 요청 헤더:
X-Forwarded-For: 192.168.1.100, 172.20.0.1
- 요청 헤더:
- 서버가 요청을 확인하면:
- request.getHeader("X-Forwarded-For") → "192.168.1.100, 172.20.0.1"
- request.getRemoteAddr() → "10.0.0.1" (로드밸런서의 IP)
- 이 경우, 첫 번째 IP(192.168.1.100)가 실제 클라이언트의 IP입니다.
4. 정리
상황 request.getRemoteAddr() request.getHeader("X-Forwarded-For")
X-Forwarded-For가 없음 | 로드밸런서 IP | null |
X-Forwarded-For가 있음 | 로드밸런서 IP | 클라이언트 IP (예: 192.168.1.100) |
다중 프록시 환경 | 마지막 프록시 IP | 여러 IP 목록 (예: 192.168.1.100, 172.20.0.1) |