소켓 피어 vs 전달된 헤더: 어느 주소를 신뢰해야 할까?
소켓 피어와 전달된 헤더는 서로 다른 증거입니다. 각각 무엇을 증명하는지 비교하고, 헤더는 자신이 통제하는 프록시 체인을 통해서만 신뢰하세요.
애플리케이션에 도착하는 요청은 두 가지 주소 증거를 담고 있습니다. 네트워크 연결을 연 피어와 이전 클라이언트의 주소를 주장하는 HTTP 필드입니다. 두 가지는 서로 다른 질문에 답합니다. 소켓 피어는 관찰되는 사실이고, 헤더는 그것을 쓴 사람이 주장하는 것일 뿐이며, 어느 것도 로그나 접근 규칙에서 다른 쪽을 조용히 대체해서는 안 됩니다. 아래 비교는 둘을 분리하고, 그다음 헤더가 쓸모 있어지는 유일한 구성만 보여 줍니다.
무엇이든 비교하기 전에 경로를 설명하십시오:
Client -> approved reverse proxy -> application origin그 구성에서 오리진의 소켓 피어는 보통 프록시이고, 전달 헤더는 프록시가 클라이언트에 대해 가진 주장을 실을 수 있습니다. 그 가치는 헤더의 이름이 아니라 그 프록시와의 통제된 관계에서 나옵니다.
두 가지 주소 증거
소켓 피어는 하나의 TCP 연결에 대한 사실입니다. 무언가가 그 주소에서 핸드셰이크를 완료했지만, 그것이 반드시 당신이 신경 쓰는 사람, 기기, 계정은 아닙니다. VPN이나 Tor 출구가 서비스가 관찰하는 출처가 되는 것도 정당하기 때문입니다. 그래도 호스트 자체가 검증한 유일한 주소이며, 그 가치의 전부가 여기에 있습니다.
전달 필드는 체인에 대한 메타데이터입니다. X-Forwarded-For, X-Real-IP 그리고 표준화된 Forwarded 필드는 그것을 되돌려 주는 엔드포인트에 도달한 어떤 클라이언트든 쓸 수 있으므로, 신뢰성은 누구에게 설정 권한이 있었는지에 전적으로 달려 있습니다.
둘 다 요청 컨텍스트에 다른 이름으로 보관하십시오. 피어를 헤더로 덮어쓰는 애플리케이션은 나중에 신뢰 오류를 재구성할 능력을 잃습니다. 바로 그때 그것이 필요합니다.
헤더는 연결 경로를 바꾸지 않는다
전달 필드에 주소를 쓰는 것은 서버에 도착하는 TCP 연결의 출처를 바꾸지 않고, 경로 어디에서도 라우팅을 바꾸지 않습니다. 일반적인 VPN 라우팅이나 출처 NAT 는 HTTP 헤더 없이 트래픽을 전달합니다. 마찬가지로 트랜짓 게이트웨이는 TLS 엔드포인트 구성을 바꾸지 않고 제대로 보호된 HTTPS 교환을 다시 쓰지 않습니다.
반대의 실수도 흔합니다. HTTPS는 클라이언트가 제공한 전달 헤더를 참으로 만들지 않습니다. 거짓 주장의 전송을 참인 주장과 똑같이 보호할 뿐입니다.
동료가 라우팅 문제를 고치기 위해 헤더 변경을 제안한다면 진단은 이미 잘못된 것입니다. 경로를 고치거나, 헤더를 쓰는 프록시 구성을 고치십시오.
주장할 권한이 있는 프록시를 지목하십시오
두 규칙이 전달 필드를 쓸모 있게 만들며, 둘 다 코드가 아니라 구성입니다. 경계는 바깥에서 오는 모든 것을 그 필드에 대한 자체 문서화된 동작에 따라 정규화하거나 버립니다. 그다음 오리진은 당신이 지목한 프록시 경로에서만 대체 주소를 가져옵니다. 두 번째 규칙은 클라이언트가 다른 방식으로 오리진에 도달할 수 없을 때만 성립합니다. 직접 요청과 프록시 요청 모두에 응답하는 오리진은 어느 쪽에 봉사하는지 알 수 없기 때문입니다.
NGINX 실제 IP 모듈 은 그 분리를 분명히 보여 줍니다. set_real_ip_from 은 주장이 계산되는 발신자를 지목하고, real_ip_header 는 어느 필드가 그것을 싣는지 말합니다. 전자는 신뢰를 수행하고, 후자는 어디를 볼지만 말합니다.
set_real_ip_from 10.20.0.0/24;
real_ip_header X-Forwarded-For;
# real_ip_recursive off - take the rightmost value in the field
# real_ip_recursive on - walk the list back past every trusted address
헤더 선택 지시문만으로는 값을 누가 보냈는지에 대해 아직 아무것도 확립하지 않습니다.
전송 보안은 신뢰하는 구성 요소 사이의 전 경로에서 작동해야 합니다. 올바르게 정규화하는 경계도 하류의 보호되지 않은 구간이 이동 중인 주장을 다른 사람이 편집하게 두는 순간 그 가치를 잃습니다.
다중 홉 체인을 의도적으로 다루십시오
여러 프록시에는 명시적 체인 모델이 필요합니다. 어떤 블로그 글이 그렇게 했다고 해서 쉼표로 구분된 가장 왼쪽이나 가장 오른쪽 값을 택하지 마십시오. 당신의 프록시 중 어느 것이 덧붙이고, 어느 것이 대체하며, 어느 것이 들어오는 필드를 보존하는지 알아내십시오. 예를 들어 NGINX는 신뢰 집합에 대고 목록을 뒤로 걸어가 자기가 소유하지 않은 첫 주소에서 멈출 수 있으며, 그것은 그 제품의 규칙이지 모든 프레임워크가 따르는 법칙이 아닙니다. 당신 프록시의 문서를 같은 두 질문으로 읽으십시오. 어느 값을 선택하며, 어느 발신자를 믿는가.
체인을 적어 두십시오. 홉 순서, 어느 홉이 필드를 설정하는지, 어느 홉이 들어오는 사본을 제거하는지입니다. 그다음 그 메모를 티켓에만 두지 말고 프록시 구성 옆에 두십시오. 그다음 승인된 검증 절차를 통해 위조 헤더가 있는 요청을 보내고 오리진이 그것을 무시하는지 확인하여 시험하십시오.
홉을 추가할 때는 그 문서를 다시 검토하십시오. 신뢰하는 프록시 앞에 삽입된 새 로드 밸런서는 누구도 애플리케이션을 편집하지 않은 채 어느 주소가 이기는지를 바꿀 수 있습니다.
두 관찰을 모두 로그에 남기십시오
진단이 허용되는 곳에서는 연결 피어와 정규화된 클라이언트 주소를 두 개의 별도 필드로 기록하고, 목적이 실제로 필요로 하는 전달 메타데이터만 추가하십시오. 그다음 두 요청으로 배포를 증명하십시오. 두 값을 합리적으로 기록해야 하는 프록시 경유 요청과 거부되어야 하는 오리진 직접 시도입니다.
이 쌍이 무엇을 뜻하는지 기억하십시오. 헤더는 당신이 신뢰하기로 고른 구성 요소가 제공하는 맥락을 더합니다. 피어는 당신의 호스트가 실제로 본 유일한 주소로 남습니다. 어느 것도 개인 신원의 증거가 아니며, 둘 중 하나를 증거로 다루는 설계는 누군가에 대해 틀릴 것입니다.