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) |
'Java' 카테고리의 다른 글
리스트처리(for -> forEach), switch (enum), Null(Optional) (1) | 2024.12.25 |
---|---|
추상화....인터페이스... (0) | 2024.12.24 |
추상 클래스 / 인터페이스 (0) | 2024.12.20 |
캡슐화 (0) | 2024.12.17 |
(지피티 선생님의) InvokeDynamic 특강 (2) | 2024.12.12 |