내용

글번호 625
작성자 heojk
작성일 2017-04-07 17:35:45
제목 Proxy(프락시) 환경에서 client IP 를 얻기 위한 X-Forwarded-For(XFF) http header
내용 Cafe24의 웹호스팅 서비스를 받고 있는데 접속로그를 분석하기 위해 로그를 데이터베이스에 저장하던중 request.getRemoteAddr() 메서드의 결과가 127.0.0.1로 출력된다. 위 문제를 해결하기 위해 X-Forwarded-For 헤더를 이용해 접속로그를 기록했다. - 개요 XFF 는 HTTP Header 중 하나로 HTTP Server 에 요청한 clinet 의 IP 를 식별하기 위한 사실상의 표준이다. 웹 서버나 WAS 앞에 L4 같은 Load balancers 나 Proxy server(HAProxy), caching server(Varnish), HTTP 서버용 WAS Connector(웹로직 커넥터 - mod_wl, 톰캣 커넥터 - mod_jk 등) 등이 있을 경우 이런 제품들은 웹서버/WAS 에 HTTP 나 전용 프로토콜(AJP)로 요청을 보낸후에 받은 결과를 가공하여 클라이언트에 재전송하게 된다. 이로 인해 처리한 웹 서버나 WAS에서 request.getRemoteAddr(); 등으로 클라이언트 IP를 얻을 경우 L4 나 Proxy 의 IP 를 얻게 되는데 이는 원하는 결과가 아니다. X-Forwarded-For는 이 문제를 해결하기 위해 사용하는 http header 로 squid caching server 에서 처음 사용되었다. 다음과 같이 콤마를 구분자로 client 와 proxy IP 가 들어가게 되므로 첫번째 IP 를 가져오면 클라이언트를 식별할 수 있다. X-Forwarded-For: client, proxy1, proxy2 - WAS 에서 사용 여기까지 읽고 웹 어플리케이션을 개발할 경우 client ip 를 식별할 필요가 있다면 먼저 저 헤더가 있는지 확인한 후에 없으면 getRemoteAddr() 로 IP 를 얻으면 되겠지라고 생각할 수도 있겠지만 이게 끝은 아니다. XFF 는 사실상의 표준이지 정식 RFC 에 포함된게 아니므로 대개는 착실하게 저 헤더를 사용하지만 엉뚱한 헤더를 사용하는 제품들이 있다. 그중에 하나인 WebLogic Connector(mod_wl) 는 저 헤더를 사용하지 않고 WL-Proxy-Client-IP 나 Proxy-Client-IP 같은 전혀 엉뚱한 헤더를 사용하므로 만약 만드는 웹 어플리케이션이 WebServer, WAS, L4, proxy 종류에 상관없이 client IP 를 잘 가져오기를 바란다면 다음과 같은 순서로 IP 를 얻어내야 한다. String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } 이외에도 X-Real-IP 나 X-RealIP 라는 헤더를 사용하는 제품도 있다고 한다. - Apache httpd Web Server 에서 사용 아파치 웹 서버에서는 LogFormat 지시자나 접근 권한 체크시 Remote Address 를 사용하는데 앞에 Reverse Proxy가 있다면 의도한 대로 동작하지 않으므로 XFF 헤더를 사용하도록 수정해야 한다. - 로그포맷 기본 로그포맷은 %h 로 리모트 Address 를 사용하므로 다음과 같이 %{X-Forwarded-For}i 를 사용하도록 수정한다. ## 수정전 ## LogFormat "%h %l %u %t \"%r\" %>s %b" common ## 수정후 LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" common 접근 제어(ACL) ACL이 필요할 경우 다음과 같이 전역 변수를 설정하고 ACL 이 필요한 곳에서 이 변수를 사용하는게 편리하다. SetEnvIf X-Forwarded-For ^192\.168\.1\. admin_1 SetEnvIf X-Forwarded-For ^192\.168\.2\. admin_2 order Deny,Allow deny from all ## 워드프레스 로그인은 내부 IP 에서만 허용 Order Deny,Allow Deny from all ## 내부 IP 만 관리자 로그인 허용 Allow From env=admin_1 Allow From env=admin_2 - nginx nginx 는 --with-http_realip_module 옵션을 주고 컴파일해야 실제 ip 를 얻어올 수 있다. 배포판에 포함된 nginx 는 기본 컴파일 옵션일것이라고 생각되며 다음 명령어로 지원 여부를 확인할 수 있다. nginx -V nginx 가 지원한다면 다음 설정을 nginx.conf 에 넣어주면 실제 ip 가 로그 파일에 기록된다. http { set_real_ip_from 127.0.0.1; # proxy/L4 서버 IP real_ip_header X-Forwarded-For; #proxy/L4 가 실제 IP 를 설정하는 HTTP Header