만족

[Express] proxy 환경에서 클라이언트의 ip 확인하기 본문

[Express] proxy 환경에서 클라이언트의 ip 확인하기

Backend/Express Satisfaction 2022. 7. 17. 19:08

결론만 보고싶다면 스크롤 맨밑으로 ㅎㅎ..

현재 apache+express 조합으로 서비스를 운영중이다.

 

client가 request를 보냈을 때 express project까지 도달하는 과정은 위와 같다.

 

 

그런데 express에서 req.ip 값을 확인하니,

전부 127.0.0.1로 찍혀 있었다.

 

왜 그럴까?

 

사실 express의 관점에서는

앞단에서 아파치가 프록시를 해주고 뭐고 그런건 관심없고

apache가 express에게 request를 보내는 것으로 인식된다.

 

따라서 자기 자신에게 포트 번호만 바꿔서 보내는 것으로 작동하므로,

요청 ip가 127.0.0.1로 찍히는 것이다.

 

req.ip

express의 req.ip는 어떻게 구현되어 있을까?

 

expressjs

https://github.com/expressjs/express/blob/master/lib/request.js

 

forwared 

https://github.com/jshttp/forwarded/blob/af3830a175dbe316be3d943f505171c73853eb04/index.js#L46

proxy-addr

https://github.com/jshttp/proxy-addr/blob/master/index.js

 

코드를 살펴보면, proxyaddr이 리턴한 값을 req.ip로 취급한다.

 

proxyaddr()은 X-Forwarded-For값을 가져와서 reverse한 후

trust()에 순차적으로 넣는 것을 반복하여

가장 먼저 나오는 not-trustable ip 또는 마지막 ip를 리턴한다.

 

다시 req.ip 구현으로 돌아와보면

req.ip는 XFF에서 가장 나중에 나오는 not-trustable한 IP값이라고 할 수 있다.

(proxyaddr은 XFF를 reverse시키고 반복문에서 필터링한다는 것을 다시 상기하자)

 

XFF(X-Forwarded-For)

https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Forwarded-For

 

X-Forwarded-For - HTTP | MDN

X-Forwarded-For (XFF) 헤더는 HTTP 프록시나 로드 밸런서를 통해 웹 서버에 접속하는 클라이언트의 원 IP 주소를 식별하는 사실상의 표준 헤더다. 클라이언트와 서버 중간에서 트래픽이 프록시나 로드

developer.mozilla.org

 

XFF는 client와 거쳐온 proxy들의 ip를 포함하고 있는 헤더 값이다.

 

클라이언트에서 출발해서, proxy를 거칠 때마다 해당 proxy-ip가 뒤에 덧붙여진다.

 

위 그림에서처럼 client-> proxy1-> proxy2-> server를 거쳤을 때,

server가 받게 되는 XFF는 <client-ip, proxy1-ip, proxy2-ip>가 된다.

 

이 구조에서 express가 받게 되는 XFF는 <client-ip, server-ip>가 되는 것을 알 수 있다.

 

위에서 req.ip 구현에 대해 살펴보았듯 proxyaddr에서 XFF를 다룰 때 

배열을 뒤집고, 가장 먼저 나오는 not-trustable ip를 리턴하므로

이 경우 <server-ip, client-ip> 에서 가장 먼저 나오는 ip인 server-ip가 req.ip로 결정된다.

 

 

trust proxy setting

이제 프록시 환경에서 왜 req.ip가 클라이언트 주소를 표시해주지 못하는지 알았다.

 

기본적으로 false로 설정되어 있어, req.ip는 XFF의 맨 마지막 IP를 리턴한다.

 

http://expressjs.com/en/4x/api.html#trust.proxy.options.table

 

Express 4.x - API Reference

Express 4.x API express() Creates an Express application. The express() function is a top-level function exported by the express module. var express = require('express') var app = express() Methods express.json([options]) This middleware is available in Ex

expressjs.com

 

우리가 원하는 것은 XFF의 첫 번째 아이피인 client-ip이다.

 

따라서 다양한 옵션 값들이 있지만, 우리는 client ip(XFF의 첫 번째 아이피)를 얻는 것이 목적이므로

trust proxy 값을 true로 설정해 준다.

 

// app.js

app.set('trust proxy', true);

이렇게 하면 모든 IP가 trustable하므로 XFF의 첫 번째 아이피(client-ip)가 req.ip값에 설정된다.

 

이제 로그에도 아이피가 정상적으로 찍힌다.

 



Comments