특수 HTTP 헤더

Tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

워드리스트 & 도구

위치를 변경할 헤더

IP 소스 재작성:

  • X-Originating-IP: 127.0.0.1
  • X-Forwarded-For: 127.0.0.1
  • X-Forwarded: 127.0.0.1
  • Forwarded-For: 127.0.0.1
  • X-Forwarded-Host: 127.0.0.1
  • X-Remote-IP: 127.0.0.1
  • X-Remote-Addr: 127.0.0.1
  • X-ProxyUser-Ip: 127.0.0.1
  • X-Original-URL: 127.0.0.1
  • Client-IP: 127.0.0.1
  • X-Client-IP: 127.0.0.1
  • X-Host: 127.0.0.1
  • True-Client-IP: 127.0.0.1
  • Cluster-Client-IP: 127.0.0.1
  • Via: 1.0 fred, 1.1 127.0.0.1
  • Connection: close, X-Forwarded-For (hop-by-hop 헤더 확인)

위치 재작성:

  • X-Original-URL: /admin/console
  • X-Rewrite-URL: /admin/console

Hop-by-Hop 헤더

Hop-by-Hop 헤더는 end-to-end 헤더와 달리 현재 요청을 처리 중인 프록시가 처리하고 소비하도록 설계된 헤더입니다.

  • Connection: close, X-Forwarded-For

hop-by-hop headers

HTTP Request Smuggling

  • Content-Length: 30
  • Transfer-Encoding: chunked

HTTP Request Smuggling / HTTP Desync Attack

Expect 헤더

클라이언트가 Expect: 100-continue 헤더를 보낸 뒤 서버가 HTTP/1.1 100 Continue로 응답하여 클라이언트가 요청 본문 전송을 계속하도록 허용하는 것이 가능합니다. 그러나 일부 프록시는 이 헤더를 제대로 좋아하지 않습니다.

Expect: 100-continue로 인한 흥미로운 결과들:

  • 본문을 가진 HEAD 요청을 보냈을 때, 서버가 HEAD 요청에는 본문이 없다는 것을 고려하지 않아 연결을 열어두고 타임아웃될 때까지 유지한 사례가 있습니다.
  • 다른 서버들은 응답에서 소켓에서 읽은 랜덤 데이터, 비밀 키 같은 이상한 데이터를 보냈거나, 프론트엔드가 헤더 값을 제거하지 못하게 하는 경우가 있었습니다.
  • 백엔드가 100 응답 대신 400 응답으로 응답했을 때 0.CL 데스싱크가 발생했습니다. 프록시 프런트엔드는 초기 요청의 본문을 보낼 준비가 되어 있었기 때문에 본문을 보내고, 백엔드는 이를 새로운 요청으로 처리했습니다.
  • Expect: y 100-continue 변형을 보내도 0.CL 데스싱크가 발생했습니다.
  • 백엔드가 404로 응답한 경우 유사한 오류로 CL.0 데스싱크가 발생했습니다. 악의적인 요청이 Content-Length를 표시하므로 백엔드는 악성 요청 + 다음 요청(피해자)의 Content-Length 바이트를 보내고, 이는 큐를 비동기화해서 백엔드는 악성 요청에 대해 404 응답과 피해자 요청들의 응답을 보내지만 프런트엔드는 하나의 요청만 보냈다고 생각하여 두 번째 응답을 다른 피해자에게 보내는 식으로 꼬입니다…

HTTP Request Smuggling에 대한 더 많은 정보는 다음을 확인하세요:

HTTP Request Smuggling / HTTP Desync Attack

캐시 헤더

서버 캐시 헤더:

  • X-Cache 응답에서 값이 **miss**이면 요청이 캐시되지 않았음을, **hit**이면 캐시되었음을 나타낼 수 있습니다.
  • Cf-Cache-Status 헤더에서도 유사한 동작을 관찰할 수 있습니다.
  • **Cache-Control**은 리소스가 캐시되는지와 다음 캐시 만료 시간을 나타냅니다: Cache-Control: public, max-age=1800
  • **Vary**는 응답에서 종종 추가 헤더들캐시 키의 일부로 취급한다고 표시할 때 사용됩니다(일반적으로 키로 사용되지 않는 헤더라도).
  • **Age**는 객체가 프록시 캐시에서 존재한 시간을 초 단위로 정의합니다.
  • **Server-Timing: cdn-cache; desc=HIT**도 리소스가 캐시되었음을 나타냅니다.

Cache Poisoning and Cache Deception

로컬 캐시 헤더:

  • Clear-Site-Data: 제거해야 할 캐시 종류를 지정하는 헤더: Clear-Site-Data: "cache", "cookies"
  • Expires: 응답이 만료되는 날짜/시간을 포함: Expires: Wed, 21 Oct 2015 07:28:00 GMT
  • Pragma: no-cacheCache-Control: no-cache와 동일함
  • Warning: 일반 HTTP 헤더인 **Warning**은 메시지 상태와 관련한 가능한 문제에 대한 정보를 포함합니다. 응답에 복수의 Warning 헤더가 나타날 수 있습니다. 예: Warning: 110 anderson/1.3.37 "Response is stale"

조건부 요청

  • If-Modified-SinceIf-Unmodified-Since 헤더를 사용한 요청은 응답 헤더 **Last-Modified**가 다른 시간을 포함하는 경우에만 데이터를 응답받습니다.
  • If-Match 및 **If-None-Match**을 사용하는 조건부 요청은 Etag 값을 사용하므로 웹 서버는 데이터(Etag)가 변경된 경우에만 응답 내용을 보냅니다. Etag는 HTTP 응답에서 가져옵니다.
  • Etag 값은 보통 응답의 내용을 기반으로 계산됩니다. 예를 들어 ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"Etag37 바이트의 Sha1임을 나타냅니다.

Range 요청

  • Accept-Ranges: 서버가 Range 요청을 지원하는지, 지원한다면 어떤 단위로 범위를 표현할 수 있는지 나타냅니다. Accept-Ranges: <range-unit>
  • Range: 서버가 반환해야 하는 문서의 부분을 나타냅니다. 예: Range:80-100은 원래 응답의 바이트 80에서 100을 반환하며 상태 코드는 206 Partial Content가 됩니다. 또한 요청에서 Accept-Encoding 헤더를 제거하는 것을 기억하세요.
  • 이는 원래라면 이스케이프되는 임의의 반사된 자바스크립트 코드를 포함한 응답을 얻는 데 유용할 수 있습니다. 하지만 이를 악용하려면 요청에 이런 헤더들을 주입해야 합니다.
  • If-Range: 주어진 etag 또는 날짜가 원격 리소스와 일치하는 경우에만 충족되는 조건부 범위 요청을 생성합니다. 서로 호환되지 않는 버전의 리소스에서 두 개의 범위를 다운로드하는 것을 방지하는 데 사용됩니다.
  • Content-Range: 부분 메시지가 전체 본문 메시지의 어디에 속하는지를 나타냅니다.

메시지 본문 정보

  • Content-Length: 리소스의 크기(십진수 바이트 수).
  • Content-Type: 리소스의 미디어 타입을 나타냄
  • Content-Encoding: 압축 알고리즘을 지정하는 데 사용됨.
  • Content-Language: 의도된 청중의 인간 언어를 설명하여 사용자가 선호하는 언어에 따라 구분할 수 있게 함.
  • Content-Location: 반환된 데이터의 대체 위치를 나타냄.

pentest 관점에서는 이 정보가 보통 “쓸모없음“인 경우가 많지만, 리소스가 401 또는 403으로 보호되어 있고 이 정보를 얻을 수 있는 어떤 방법을 찾을 수 있다면 흥미로울 수 있습니다.
예를 들어 HEAD 요청에서 **Range**와 **Etag**의 조합은 HEAD 요청을 통해 페이지의 내용을 leak할 수 있습니다:

  • 헤더 Range: bytes=20-20로 요청하고 응답에 ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"가 포함되어 있다면, 바이트 20의 SHA1이 ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y임을 leak하고 있는 것입니다.

서버 정보

  • Server: Apache/2.4.1 (Unix)
  • X-Powered-By: PHP/5.3.3

제어 헤더

  • Allow: 이 헤더는 리소스가 처리할 수 있는 HTTP 메서드를 전달하는 데 사용됩니다. 예: Allow: GET, POST, HEAD는 리소스가 이 메서드들을 지원함을 나타냅니다.
  • Expect: 클라이언트가 요청을 성공적으로 처리하기 위해 서버가 충족해야 할 기대 사항을 전달하는 데 사용됩니다. 일반적인 사용 사례는 큰 데이터를 전송하려는 클라이언트가 보내는 Expect: 100-continue 헤더로, 클라이언트는 전송을 계속하기 전에 100 (Continue) 응답을 기다립니다. 이 메커니즘은 서버 확인을 기다림으로써 네트워크 사용을 최적화하는 데 도움을 줍니다.

다운로드

HTTP 응답의 Content-Disposition 헤더는 파일을 웹페이지 내에서 표시할지(인라인) 아니면 **첨부(다운로드)**로 처리할지 지시합니다. 예를 들면:

Content-Disposition: attachment; filename="filename.jpg"

이는 “filename.jpg“라는 파일이 다운로드되어 저장되어야 함을 의미합니다.

보안 헤더

콘텐츠 보안 정책 (CSP)

Content Security Policy (CSP) Bypass

Trusted Types

CSP를 통해 Trusted Types를 강제하면 애플리케이션을 DOM XSS 공격으로부터 보호할 수 있습니다. Trusted Types는 보안 정책을 준수하는 특정하게 제작된 객체만이 위험한 web API 호출에 사용되도록 보장하여 JavaScript 코드를 기본적으로 안전하게 만듭니다.

// Feature detection
if (window.trustedTypes && trustedTypes.createPolicy) {
// Name and create a policy
const policy = trustedTypes.createPolicy('escapePolicy', {
createHTML: str => str.replace(/\</g, '&lt;').replace(/>/g, '&gt;');
});
}
// Assignment of raw strings is blocked, ensuring safety.
el.innerHTML = "some string" // Throws an exception.
const escaped = policy.createHTML("<img src=x onerror=alert(1)>")
el.innerHTML = escaped // Results in safe assignment.

X-Content-Type-Options

이 헤더는 MIME type sniffing을 방지합니다. 이는 XSS 취약점으로 이어질 수 있습니다. 브라우저가 서버에서 지정한 MIME 타입을 존중하도록 보장합니다.

X-Content-Type-Options: nosniff

X-Frame-Options

이 헤더는 clickjacking을 방지하기 위해 문서가 <frame>, <iframe>, <embed>, 또는 <object> 태그에 어떻게 포함될 수 있는지를 제한하며, 모든 문서가 포함 허용을 명시적으로 지정할 것을 권장합니다.

X-Frame-Options: DENY

크로스-오리진 리소스 정책 (CORP) 및 크로스-오리진 리소스 공유 (CORS)

CORP는 웹사이트에서 로드할 수 있는 리소스를 지정하는 데 매우 중요하며, cross-site leaks를 완화합니다. CORS는 반면 보다 유연한 cross-origin 리소스 공유 메커니즘을 허용하여 특정 조건에서 same-origin policy를 완화합니다.

Cross-Origin-Resource-Policy: same-origin
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

교차 출처 임베더 정책 (COEP) 및 교차 출처 오프너 정책 (COOP)

COEP와 COOP는 교차 출처 격리를 가능하게 하는 데 필수적이며, Spectre-like attacks의 위험을 크게 줄여줍니다. 이들은 각각 교차 출처 리소스의 로딩과 교차 출처 창과의 상호작용을 제어합니다.

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin-allow-popups

HTTP Strict Transport Security (HSTS)

마지막으로, HSTS는 브라우저가 서버와 오직 안전한 HTTPS 연결로만 통신하도록 강제하는 보안 기능으로, 이로써 개인정보 보호와 보안을 강화합니다.

Strict-Transport-Security: max-age=3153600

Permissions-Policy (formerly Feature-Policy)

Permissions-Policy는 웹 개발자가 문서 내에서 특정 브라우저 기능과 API의 동작을 선택적으로 활성화·비활성화하거나 수정할 수 있게 합니다. 이는 현재 폐기된 Feature-Policy 헤더의 후속입니다. 이 헤더는 악용될 수 있는 강력한 기능에 대한 접근을 제한하여 attack surface를 줄이는 데 도움을 줍니다.

Permissions-Policy: geolocation=(), camera=(), microphone=()

일반 디렉티브:

디렉티브설명
accelerometerAccelerometer 센서에 대한 접근을 제어합니다
camera비디오 입력 장치(웹캠)에 대한 접근을 제어합니다
geolocationGeolocation API에 대한 접근을 제어합니다
gyroscopeGyroscope 센서에 대한 접근을 제어합니다
magnetometerMagnetometer 센서에 대한 접근을 제어합니다
microphone오디오 입력 장치에 대한 접근을 제어합니다
paymentPayment Request API에 대한 접근을 제어합니다
usbWebUSB API에 대한 접근을 제어합니다
fullscreenFullscreen API에 대한 접근을 제어합니다
autoplay미디어의 자동 재생 허용 여부를 제어합니다
clipboard-read클립보드 내용을 읽는 접근을 제어합니다
clipboard-write클립보드에 쓰는 접근을 제어합니다

구문 값:

  • () - 기능을 완전히 비활성화합니다
  • (self) - 동일한 출처에서만 기능을 허용합니다
  • * - 모든 출처에 대해 기능을 허용합니다
  • (self "https://example.com") - 동일 출처와 지정된 도메인에 대해 허용합니다

예제 구성:

# Restrictive policy - disable most features
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=(), usb=()

# Allow camera only from same origin
Permissions-Policy: camera=(self)

# Allow geolocation for same origin and a trusted partner
Permissions-Policy: geolocation=(self "https://maps.example.com")

From a security perspective, missing or overly permissive Permissions-Policy headers may allow attackers (e.g., through XSS or embedded iframes) to abuse powerful browser features. Always restrict features to the minimum necessary for your application.

Header Name Casing Bypass

HTTP/1.1 defines header field‐names as case-insensitive (RFC 9110 §5.1). Nevertheless, it is very common to find custom middleware, security filters, or business logic that compare the literal header name received without normalising the casing first (e.g. header.equals("CamelExecCommandExecutable")). If those checks are performed case-sensitively, an attacker may bypass them simply by sending the same header with a different capitalisation.

Typical situations where this mistake appears:

  • Custom allow/deny lists that try to block “dangerous” internal headers before the request reaches a sensitive component.
  • In-house implementations of reverse-proxy pseudo-headers (e.g. X-Forwarded-For sanitisation).
  • Frameworks that expose management / debug endpoints and rely on header names for authentication or command selection.

Abusing the bypass

  1. Identify a header that is filtered or validated server-side (for example, by reading source code, documentation, or error messages).
  2. Send the same header with a different casing (mixed-case or upper-case). Because HTTP stacks usually canonicalise headers only after user code has run, the vulnerable check can be skipped.
  3. If the downstream component treats headers in a case-insensitive way (most do), it will accept the attacker-controlled value.

Example: Apache Camel exec RCE (CVE-2025-27636)

In vulnerable versions of Apache Camel the Command Center routes try to block untrusted requests by stripping the headers CamelExecCommandExecutable and CamelExecCommandArgs. The comparison was done with equals() so only the exact lowercase names were removed.

# Bypass the filter by using mixed-case header names and execute `ls /` on the host
curl "http://<IP>/command-center" \
-H "CAmelExecCommandExecutable: ls" \
-H "CAmelExecCommandArgs: /"

헤더가 필터링되지 않은 채 exec 컴포넌트에 도달하여 Camel 프로세스의 권한으로 remote command execution을 초래합니다.

탐지 및 완화

  • 허용/거부 비교를 수행하기 이전에, 모든 헤더 이름을 하나의 케이스(보통 소문자)로 정규화하세요.
  • 의심스러운 중복을 거부하세요: Header:HeAdEr:가 동시에 존재하면 이를 이상(anomaly)으로 처리하세요.
  • 정규화 이후에 적용되는 긍정적 허용 목록(allow-list)을 사용하세요.
  • 관리용 엔드포인트는 인증과 네트워크 분리로 보호하세요.

참고자료

Tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기