이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • 인증, 추적, 캐시, forwarding, rate limit, 보안 header를 운영 계약으로 어떻게 설계하는가?
  • proxy를 지나며 header가 추가, 제거, 병합, 정규화될 때 어떤 장애와 보안 문제가 생기는가?
  • X-Forwarded-*, Forwarded, traceparent, X-Request-ID를 어느 신뢰 경계에서 사용할 수 있는가?

개요

Header는 HTTP의 운영 메타데이터다. 인증, 세션, 캐시, tracing, content negotiation, rate limit, proxy forwarding, 보안 정책이 header로 표현된다. header 하나가 라우팅, 인증, 캐시, 로그 연결을 바꿀 수 있다.

  • Header는 HTTP의 운영 메타데이터다.
  • Authorization, Cookie, Cache-Control, X-Request-ID, Forwarded는 장애와 보안을 직접 좌우한다.
  • 프록시를 지날 때 추가·삭제·변조되는 header를 이해해야 한다.

왜 백엔드 개발자가 알아야 하는가

header는 클라이언트가 조작할 수 있고, proxy가 바꿀 수 있고, 앱이 신뢰할 수도 있다. 이 신뢰 경계를 잘못 잡으면 보안 사고와 운영 장애가 함께 생긴다.

  • X-Forwarded-For를 무조건 믿으면 client IP spoofing이 가능하다.
  • Authorization이나 Cookie가 로그에 남으면 credential leak가 된다.
  • Cache-Control이나 Vary가 틀리면 개인화 응답이 cache될 수 있다.
  • X-Request-ID가 끊기면 CDN, gateway, app log를 연결하기 어렵다.
  • header size가 커지면 400/431/502가 날 수 있다.

요청 흐름에서의 위치

header는 client부터 app까지 계속 추가되고 해석된다.

Client headers
→ CDN/WAF adds/filters headers
→ LB/Gateway adds X-Forwarded-* or Forwarded
→ App trusts selected headers only from trusted proxy
→ App returns cache/security/rate-limit headers

문제는 “헤더가 있다”가 아니라 “누가 만든 헤더이며 어느 지점부터 신뢰할 수 있는가”다.

원리

주요 header를 역할별로 나누면 다음과 같다.

범주예시실무 포인트
인증/세션Authorization, Cookie, Set-Cookie절대 평문 로그 금지
tracingtraceparent, X-Request-ID계층 간 로그 연결
forwardingForwarded, X-Forwarded-For, X-Forwarded-Prototrusted proxy 경계 필요
cacheCache-Control, ETag, VaryCDN/browser cache 제어
negotiationAccept, Content-Type, Accept-Encoding406/415/encoding 판단
rate limitRetry-After, RateLimit-*client backoff 유도
securityStrict-Transport-Security, Content-Security-Policybrowser 보안 정책

HTTP header field name은 대소문자를 구분하지 않는다. 하지만 일부 framework, gateway, legacy system은 중복 header나 underscore 처리에서 차이를 보이므로 운영에서 실제 전달 형태를 확인해야 한다.

핵심 판단 기준

  • 앱이 신뢰하는 inbound header 목록을 문서화한다.
  • forwarding header는 trusted proxy에서 온 요청에 대해서만 사용한다.
  • tracing header는 새로 만들지, 이어받을지, 덮어쓸지 정책을 둔다.
  • header log는 allowlist 기반으로 남기고 민감 header는 mask/drop한다.
  • header size limit은 CDN/WAF/proxy/app에서 맞춘다.

실무에서 자주 만나는 문제

  • 민감 정보를 커스텀 header로 남겨 로그에 유출한다.
  • 대소문자나 중복 header 처리 차이를 놓친다.
  • forwarded header를 신뢰 경계 없이 믿는다.
  • client가 임의로 X-Forwarded-For를 넣어 rate limit이나 audit log를 우회한다.
  • gateway가 Authorization을 제거하고 X-User-ID를 넣는데 app이 양쪽을 동시에 신뢰한다.
  • X-Request-ID가 edge에서 새로 생성되고 app에서 다시 생성되어 trace가 끊긴다.
  • Vary가 없어 language/encoding별 cache가 섞인다.
  • header가 너무 커져 431이나 upstream 502가 난다.

header 문제는 특정 proxy 경유, 특정 client SDK, 특정 browser에서만 나타날 수 있다. raw request를 재현하고 각 계층에서 실제로 받은 header를 비교해야 한다.

디버깅 방법

  • curl -v--trace-ascii로 실제 header를 확인한다.
  • gateway와 app access log의 request id가 같은지 본다.
  • X-Forwarded-For chain에서 trusted proxy 뒤의 값만 client IP로 쓰는지 확인한다.
  • header size 관련 오류는 proxy error log와 app server limit을 같이 본다.
  • 보안 header는 브라우저 DevTools Security/Network 탭에서 확인한다.

코드로 확인하기

curl -v https://api.example.com/orders/1 \
  -H 'X-Request-ID: local-test-001' \
  -H 'X-Forwarded-For: 1.2.3.4' \
  -H 'Accept: application/json'

테스트 목적으로 보낸 X-Forwarded-For를 앱이 그대로 신뢰하면 위험하다. edge나 trusted proxy에서 들어온 값만 신뢰해야 한다.

proxy_set_header Host $host;
proxy_set_header X-Request-ID $request_id;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

이 설정을 쓴다면 app은 “이 NGINX를 통과한 요청”에서만 forwarded header를 신뢰해야 한다.

주니어가 자주 하는 오해

  • header는 모두 서버가 만든 값이라고 생각한다.
    • request header는 client가 조작할 수 있다.
  • X-Forwarded-For의 첫 번째 IP를 무조건 client IP로 믿는다.
    • trusted proxy chain을 기준으로 해석해야 한다.
  • header 이름 대소문자를 구분한다고 생각한다.
    • HTTP header field name은 대소문자를 구분하지 않는다.
  • 디버깅을 위해 모든 header를 로그에 남겨도 된다고 생각한다.
    • 인증 토큰과 cookie가 유출될 수 있다.

시니어의 설계 판단 기준

  • 표준 header를 우선 쓰고, custom header는 naming과 ownership을 정한다.
  • inbound trust boundary를 설계한다. 외부 client header와 internal gateway header를 같은 수준으로 보지 않는다.
  • log에 남길 header allowlist와 masking 정책을 둔다.
  • request id와 traceparent의 생성/전파 책임을 한 곳에 정한다.
  • header size budget을 둔다. JWT, cookie, custom metadata가 커지면 431/502와 latency 문제가 생긴다.

인프라 협업 포인트

  • proxy가 어떤 header를 추가/삭제/덮어쓰는지 표로 합의한다.
  • client IP를 어떤 header에서 읽고 어떤 proxy chain을 신뢰할지 정한다.
  • WAF/edge에서 차단된 요청에도 request id나 rule id를 남길 수 있는지 확인한다.
  • 인프라 팀은 header가 보안 정책, routing, cache, observability를 동시에 건드려 변경 위험이 큰 점을 관리해야 한다.

실전 팁

  • request id는 response header로 되돌려 주면 client 제보가 쉬워진다.
  • Authorization, Cookie, Set-Cookie는 기본적으로 로그 금지다.
  • custom header는 API 문서에 방향(request/response), 필수 여부, 민감도, 예시를 둔다.
  • header 변경은 cache와 CORS, WAF rule에 영향을 줄 수 있으므로 배포 노트에 남긴다.

위험 신호!

  • X-Forwarded-*를 외부 요청에서도 그대로 신뢰한다.
  • Authorization/Cookie가 평문 로그에 남는다.
  • request id가 계층마다 새로 생성되어 연결되지 않는다.
  • header size limit이 문서화되어 있지 않다.
  • custom header가 많지만 owner와 의미가 없다.

확인 질문

확인 질문

  • forwarding header를 무조건 신뢰하면 왜 위험한가?
    • client가 직접 조작할 수 있어 IP 기반 rate limit, audit, redirect, security 판단을 우회할 수 있기 때문이다.
  • request id를 response header로 돌려주는 이유는 무엇인가?
    • client가 본 장애와 서버/프록시 로그를 같은 요청으로 연결할 수 있기 때문이다.
  • header 로그 정책에서 가장 먼저 정해야 할 것은 무엇인가?
    • 어떤 header를 남길지 allowlist와 어떤 값을 mask/drop할지 민감정보 기준을 정해야 한다.

참고 문서