Proxy와 사용자 IP(X-Forwarded-For(XFF))
개요
X-Forwarded-For(XFF) 란?
- XFF 는 HTTP Header 중 하나로 HTTP Server 에 요청한 Client 의 IP 를 식별하기 위한 표준
- 웹 서버나 WAS 앞에 L4 같은 Load balancers 나 Proxy server, caching server 등의 장비가 있을 경우,
웹서버는 Proxy server 이나 장비 IP 에서 접속한 것으로 인식
==> 웹 서버는 실제 클라이언트 IP가 아니라 앞단 Proxy 서버 를 요청한 IP로 인식 / Proxy 장비 IP로 웹 로그 남김
웹 프록시 동작에서의 사용자 IP 변환
1번 과정에서 클라는 웹 서버와 세션을 맺으려하나 실제로는 웹 프록시와 TCP 세션을 맺게 되며
3번 과정에서 웹 서버는 클라이언트와 TCP 세션을 맺으려 하나 웹 프록시와 TCP 세션을 맺게 됨.
==> 지연 바인딩 과정(Delayed Binding)
3번의 과정에서부터 웹 프록시와 웹 서버 간의 동작에서 소스 IP가 웹프록시 IP로 변경되며
그로 인해 웹 서버는 실제 사용자 IP를 확인하지 못합니다.
IP 변경에 따른 고려사항
사용자 IP가 변경되게 된다면
해당 데이터를 통해 수집되는 로그에서 사용자 IP를 구별할 수 없어
사용자 IP 기반의 서비스 및 정책들에 제약이 걸려 사용할 수 없게 되기 때문에 클라이언트 IP를 찾을 수 있어야 합니다.
XFF
HTTP 프록시나 LB를 통해 웹 서버에서 접속하는 클라이언트의 실제 IP주소를 식별하는 표준 헤더로
문법은 아래와 같습니다.
X-Forwarded-For: <client>, <proxy1>, <proxy2>
- client : 클라이언트 ip 주소
- proxy1, proxy2 : 하나의 요청이 여러 프록시를 거치면 각 프록시 ip주소들이 차례로 열거 / 가장 오른쪽 ip 주소가 가장 마지막에 거친 프록시 ip 주소
관련 코드
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
# WAS(WebLogic)의 webserver 연계 모듈인 weblogic connector 에서 사용되는 헤더
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
# WAS(WebLogic)의 webserver 연계 모듈인 weblogic connector 에서 사용되는 헤더
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
# PHP . ASP 에서 실제 Clinet IP를 구할때 사용하는 헤더
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
# PHP . ASP 에서 실제 Clinet IP를 구할때 사용하는 헤더
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
PHP 사용방식
function getRealClientIp() {
...
if (getenv('HTTP_CLIENT_IP')) {
ip = getenv('HTTP_CLIENT_IP');
}
if(getenv('HTTP_X_FORWARDED_FOR')) {
ip = getenv('HTTP_X_FORWARDED_FOR');
}
...
}
ASP 사용방식
string ip = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if(string.IsNullOrEmpty(ipaddr)) {
ip = Request.ServerVariables["REMOTE_ADDR"];
}