[Django] Request Header 활용 1 : 클라이언트 IP 탐색

David Im·2022년 8월 9일
1

본 글은 야간모드에 최적화 되어있습니다. 우측 상단에서 해 혹은 달모양을 클릭시어 velog 설정을 야간모드로 해주시면 더욱 편안하게 읽으실 수 있습니다.

처음에는 PC 웹 위주로 서비스를 운영했지만, 점차 서비스가 확장되고 글로벌 서비스를 진행하는 회사이다보니 접속자의 IP에 대한 국가 판별과 언어, 그리고 접속 디바이스에 대한 구분이 필요해졌다.

그래서 어떤 방식으로 가져올 수 있을까 생각을 하다가 접속한 브라우저에서 정보를 얻어올 수 있지 않을까 싶었다.

브라우저에서 접속할 때 어떤방식으로든 api request가 일어날 테니, 그 request의 header 안에 있는 정보를 활용해 보자는 생각이 들었다.

그 첫번째로, IP 파악에 대해서 작성해본다.

Request Header를 통한 IP 파악

찾아보니 request 안에서 X_Forward_For와 Remote_ADDR 이라는것을 활용하여 클라이언트의 IP를 얻을 수 있다고 한다.

방법은 간단했지만 방식과 원리도 궁금해서 조금 더 찾아보고 함께 작성해본다.

HTTP_X_Forwarded_for (XFF) 와 REMOTE_ADDR

XFF는 HTTP Header 중 하나로 HTTP Server 에 요청한 clinet 의 IP 를 식별하기 위한 것이라고 한다.

우리가 어떠한 클라이언트의 IP 주소를 Request 안에서 얻으려고할 때 두가지가 존재하게 되는데, 그것이 바로 XFF와 RemoteADDR이다.

원래 실제 IP는 RemoteADDR에 가지고 있게되는데, Proxy 서버를 거치게되면 해당 값으로는 정확한 클라이언트의 IP를 알수없다.

그래서 존재하는것이 XFF인데, 이 값은 우리가 얻으려는 실제 IP로, 엄연하게 말하면 이 XFF는 Proxy 서버가 설정해주는 환경 변수이다.

클라이언트가 Proxy 서버를 통하여 요청을 보낼 경우 서버로 전송 되는 클라이언트 IP 정보인 Remote_ADDR은 더 이상 실제 IP가 아니게되고 Proxy 서버 IP 정보로 설정되어 전송되게 된다.

Via: 1.1 proxy.smileserv.com:80 (squid)
X-Forwarded-For: 220.90.215.4 # Proxy를 거쳐 request 요청을 하게된 IP
Cache-Control: max-age=259200
Connection: keep-alive

즉, Proxy를 거치게 되면 Proxy 서버가 설정해준 환경변수인 X_FROWARDED_FOR에 위 헤더 처럼 실제 IP값과 Proxy ip가 실려 전송을 요청하게되어 해당 부분의 맨 첫번째 IP가 실제 요청 IP가 된다.

그럼 왜 바꿔주는지도 궁금해져서 더 찾아보았다.

HTTP_X_FORWARDED_FOR를 사용하는 이유

웹 서버나 WAS 앞에 L4 같은 로드밸런서나 Proxy 서버, 캐싱 서버 등이 존재하는 경우에 웹서버는 Proxy 서버나 장비 IP 에서 접속한 것으로 인식하게 된다고 한다.

그렇기 때문에 웹서버는 실제 클라이언트 IP 가 아닌 앞단에 있는 Proxy 서버 IP 를 요청한 IP 로 인식하고, Proxy 장비 IP 로 웹로그를 남기게 된다.

클라이언트 IP ⟶ Proxy 서버 및 장비 ⟶ 웹 서버

이때 웹 프로그램에서는 Request Header 내에 있는 XFF를 통해 클라이언트 IP를 찾아 실제 요청한 클라이언트 IP 를 알 수 있고, 웹로그에도 실제 요청한 클라이언트 IP 를 남길 수 있게된다.

X-Forwarded-For: client, proxy1, proxy2

위와 같이 X-Forwarded-For 는 다음과 같이 콤마를 구분자로 Client 와 Proxy IP 가 들어가게 되므로 첫번째 IP 를 가져오면 클라이언트의 실제 IP가 어떤 것인지 알 수 있다.

추가적으로 Apache 나 Nginx에서 XFF를 사용하려면 추가적인 설정이 필요하다고 하니 필요하신분들은 검색해보시기를 바란다.

Django에서 클라이언트의 IP 탐색하기

위에서 설명한 이유와 같이, 우리는 Proxy를 거친다하더라도 변조되지 않은 클라이언트의 실제 IP가 필요하다. Django에서도 Request 모듈을 통해서 이 기능을 지원하고 있다.

x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')

if x_forwarded_for:
	ip = x_forwarded_for.split(',')[0]
else:
	ip = request.META.get('REMOTE_ADDR')
return ip

request 메타정보에서 우선적으로 X_FORWARDED_FOR가 존재하는지를 탐색한다. 해당 값이 존재한다면 Proxy 값이 아닌 첫번째의 client IP 값을 가져와서 IP를 리턴해주고, 그렇지 않다면 Proxy를 거치지 않은 순수한 IP이므로 REMOTE_ADDR의 값을 사용하여 IP를 리턴해준다.

다른곳에서도 사용하는 방식은 비슷하더라.

짧지만 굉장히 유용하게 사용할 수 있는 코드인것 같고 header내에 수많은 값들 중에서 다른 부분들도 활용할 수 있다면 더 많은 정보를 활용할 수 있지 않을까 싶었다.

예를 들자면, 네이버나 이런곳에서도 사용하고있는 현재 접속위치와 다른위치에서 접속했을때 alert 페이지나 , 동시접속 기기에 대한 정보들 같은 것들?


참고자료

profile
코더보다 개발자로, 결과와 과정의 시너지를 만들어 가고 싶은 주니어 개발자

0개의 댓글