Nginx real IP 모듈은 set_real_ip_from에 등록한 신뢰 주소가 보내는 헤더를 기준으로 client 주소를 바꿉니다. real_ip_recursive on이면 신뢰된 주소 체인을 따라 헤더에서 마지막 비신뢰 주소를 선택합니다.
$realip_remote_addr는 real IP 처리 전 원래 연결 주소를 보존합니다. X-Forwarded-For 자체를 무조건 신뢰할 수는 없으며, 실제 proxy CIDR과 헤더를 정리하는 ingress 동작을 확인해야 합니다.
X-Forwarded-For는 증거가 아니라 입력값입니다
Nginx가 reverse proxy 뒤에 있으면 TCP 연결에서 직접 보이는 peer는 최종 client가 아니라 바로 앞 proxy일 수 있습니다. real IP 모듈은 설정한 헤더에서 주소를 읽어 Nginx가 사용하는 client 주소를 바꿀 수 있습니다. 이 기능은 set_real_ip_from으로 올바른 대체 주소를 보낼 것으로 신뢰하는 proxy 주소를 선언하는 방식입니다. 그래서 X-Forwarded-For라는 이름이 있다는 이유만으로 그 안의 왼쪽 첫 주소를 진짜 사용자 IP라고 믿으면 안 됩니다. 누가 헤더를 만들었는지와 중간 proxy가 값을 추가·정리했는지 확인해야 합니다.
# 가상 예: 승인된 proxy 범위를 실제 목록으로 대체해야 함
set_real_ip_from 198.51.100.0/24;
set_real_ip_from 192.0.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;신뢰한 hop을 오른쪽에서 따라가며 주소를 고릅니다
| 체인 요소 | 주소 예시 | 설정상 신뢰 여부 | 판독 |
|---|---|---|---|
| client | 203.0.113.44 | 비신뢰 | 체인 왼쪽에 있는 후보 client |
| 내부 proxy | 192.0.2.18 | 신뢰 | 실제 구성에서 해당 proxy가 신뢰 범위에 있을 때만 통과 |
| edge proxy / Nginx의 원래 peer | 198.51.100.27 | 신뢰 | Nginx에 직접 연결한 마지막 proxy |
가상 X-Forwarded-For 값이 203.0.113.44, 192.0.2.18이고 Nginx의 직접 peer가 198.51.100.27이라고 하겠습니다. 두 proxy 대역을 신뢰하고 real_ip_recursive on이면 오른쪽 신뢰 hop을 지나 마지막 비신뢰 주소 203.0.113.44가 선택됩니다. $remote_addr에는 처리 뒤 선택한 주소가, $realip_remote_addr에는 원래 peer인 198.51.100.27이 남습니다. 내부 proxy 주소를 신뢰 목록에서 빼면 탐색이 그곳에서 멈출 수 있습니다. 재귀 처리를 끄면 마지막으로 보낸 헤더 주소를 쓰므로 결과가 달라집니다.
헤더를 보내는 proxy와 받는 Nginx를 함께 확인합니다
real IP 모듈은 신뢰 목록과 header 값을 함께 사용합니다. upstream에 전달할 헤더는 Nginx의 proxy_set_header로 다시 정의하거나 추가할 수 있습니다. 하지만 이 지시문만으로 앞단 load balancer나 CDN이 어떤 값을 받았는지 알 수는 없습니다. ingress가 요청자가 보낸 X-Forwarded-For를 정리한 뒤 신뢰된 hop을 기록하는지 확인해야 합니다. 신뢰 CIDR에 실제 proxy가 아닌 넓은 고객망을 넣거나 필요한 hop을 빼면 주소가 잘못 계산될 수 있습니다.
- Nginx가 real IP 모듈을 포함해 빌드됐는지 확인합니다. 공식 문서상 이 모듈은 기본 빌드에 포함되지 않을 수 있습니다.
- 요청을 직접 전달하는 peer와 그 앞의 proxy 구간을 네트워크 구성 자료로 확인합니다.
set_real_ip_from을 실제 신뢰 proxy 주소로만 한정하고real_ip_header가 실제 전달 헤더와 일치하는지 검토합니다.real_ip_recursive값을 확인한 뒤 교육용 체인처럼 오른쪽에서 신뢰·비신뢰 hop을 손으로 표시합니다.- 로그의
$remote_addr뿐 아니라 원래 연결 peer인$realip_remote_addr와 ingress의 헤더 처리 기록을 함께 비교합니다.
신뢰 범위를 넓게 잡으면 공격자 입력을 주소로 채택할 수 있습니다
첫 번째 실수는 set_real_ip_from 0.0.0.0/0;처럼 모든 송신지를 신뢰하는 식의 넓은 범위를 별 검증 없이 쓰는 것입니다. 그러면 요청자가 조작한 header가 신뢰된 교체 값처럼 취급될 위험이 커집니다. 두 번째는 모든 proxy가 같은 헤더 순서와 정규화 규칙을 쓴다고 가정하는 것입니다. 세 번째는 $remote_addr만 남기고 원래 peer 변수를 기록하지 않아 어느 proxy에서 온 요청인지 추적할 단서를 없애는 것입니다. 실제 로그 신뢰도는 Nginx 지시문만이 아니라 앞단 proxy의 동작과 운영자가 정한 CIDR 경계에도 달려 있습니다.
주소 체인과 신뢰 목록을 나란히 적습니다
조사표의 한쪽에는 연결 peer, X-Forwarded-For 각 항목을 오른쪽에서 왼쪽으로 적고, 다른 쪽에는 실제로 신뢰한다고 검증한 CIDR을 씁니다. 가장 오른쪽의 직접 peer가 신뢰되는지 먼저 확인하고, 신뢰되는 헤더 hop을 하나씩 건너뛰다가 처음 만난 비신뢰 주소를 표시합니다. 그 주소를 곧바로 사용자 신원으로 확정하지 말고 ingress가 헤더를 검증·정리했다는 별도 증거와 맞춰 보세요. 여기서 쓴 IPv4 대역은 설명을 위한 문서용 주소일 뿐, 사용할 CIDR을 제안하지 않습니다.
정답을 가리고 확인해 보세요
이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.
직접 연결 peer 198.51.100.27과 헤더 주소 203.0.113.44, 192.0.2.18이 있고, 두 proxy 대역은 모두 set_real_ip_from으로 신뢰하며 real_ip_recursive on입니다. real_ip 모듈은 어떤 헤더 주소를 선택하나요? $realip_remote_addr는 무엇을 보존하나요?
정답과 해설 확인
마지막 비신뢰 주소인203.0.113.44를 선택합니다. $realip_remote_addr는 원래 연결 peer인 198.51.100.27을 보존합니다.Nginx 문서는 recursive 검색이 켜져 있으면 원래 peer가 신뢰 주소인 경우 X-Forwarded-For 체인에서 마지막 비신뢰 주소를 사용한다고 설명합니다. realip_remote_addr 변수에는 real IP 처리 전 원래 client address가 남습니다. 이 결과는 신뢰 목록과 앞단 proxy의 헤더 처리 가정이 맞을 때만 유효합니다.