이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- 인증, 추적, 캐시, 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 | 절대 평문 로그 금지 |
| tracing | traceparent, X-Request-ID | 계층 간 로그 연결 |
| forwarding | Forwarded, X-Forwarded-For, X-Forwarded-Proto | trusted proxy 경계 필요 |
| cache | Cache-Control, ETag, Vary | CDN/browser cache 제어 |
| negotiation | Accept, Content-Type, Accept-Encoding | 406/415/encoding 판단 |
| rate limit | Retry-After, RateLimit-* | client backoff 유도 |
| security | Strict-Transport-Security, Content-Security-Policy | browser 보안 정책 |
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-Forchain에서 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할지 민감정보 기준을 정해야 한다.