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
  
<Files wp-config.php>
    order Deny,Allow
    deny from all
</Files>
 
## 워드프레스 로그인은 내부 IP 에서만 허용
<Files ~ "^wp-login.php">
    Order Deny,Allow
    Deny from all
## 내부 IP 만 관리자 로그인 허용
    Allow From env=admin_1
    Allow From env=admin_2
</Files>

 

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


'Server Enterprise > Java' 카테고리의 다른 글

[Split] | 자르기  (0) 2018.04.26
[Java] Json 파싱  (0) 2018.03.05
[알고리즘] 문제 출제 및 유용한 사이트  (0) 2016.08.08
[Java] Design Pattern  (0) 2016.07.07
[Book] 알고리즘 관련 서적 for java  (0) 2016.07.05

+ Recent posts