特殊な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 ヘッダは、エンドツーエンドのヘッダとは異なり、現在リクエストを処理しているプロキシによって処理・消費されることを意図したヘッダです。

  • 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 の desync が発生したことがある。プロキシのフロントエンドは元のリクエストのボディを送る準備をしていたためボディを送信し、バックエンドはそれを新しいリクエストとして扱った。
  • Expect: y 100-continue のような変種でも 0.CL の desync を引き起こした。
  • バックエンドが 404 で応答した類似のエラーは CL.0 の desync を生成した。悪意あるリクエストが Content-Length を示しているため、バックエンドは悪意あるリクエスト + 次のリクエスト(被害者)の Content-Length バイトを送ってしまい、キューがずれてしまう。結果として、バックエンドは悪意あるリクエストに対して 404 を返し + 被害者のレスポンスを返すが、フロントエンドは送信されたのが1つのリクエストだけだと思っているため、2つ目のレスポンスが別の被害者リクエストに送られ、そのレスポンスはさらに次へと渡されてしまう…

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: 110 anderson/1.3.37 "Response is stale"

条件付きリクエスト

  • If-Modified-SinceIf-Unmodified-Since を使ったリクエストは、レスポンスヘッダ Last-Modified が異なる時間を含む場合にのみデータで応答されます。
  • If-MatchIf-None-Match を使う条件付きリクエストは ETag 値を使い、サーバはデータ(Etag)が変更されている場合にレスポンスの内容を返します。Etag は HTTP レスポンスから取得されます。
  • Etag 値は通常レスポンスの コンテンツに基づいて計算されます。例えば、ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI" は、その Etag37 バイトSha1 に基づいていることを示します。

Range リクエスト

  • Accept-Ranges: サーバがレンジリクエストをサポートしているかどうか、サポートしている場合はどの単位でレンジを表現できるかを示します。Accept-Ranges: <range-unit>
  • Range: サーバが返すべきドキュメントの部分を示します。例えば Range:80-100 は元のレスポンスのバイト 80 から 100 を返し、ステータスコード 206 Partial Content を返します。リクエストから Accept-Encoding ヘッダを削除することを忘れないでください。
  • これは、本来エスケープされるはずの任意の反射された javascript コードを含むレスポンスを得るのに有用な場合があります。ただしこれを悪用するにはリクエストにこれらのヘッダを注入する必要があります。
  • If-Range: 指定された etag または日時がリモートリソースと一致する場合にのみ満たされる条件付きレンジリクエストを作成します。異なるバージョンのリソースから2つのレンジをダウンロードするのを防ぐために使われます。
  • Content-Range: 部分メッセージが完全なボディメッセージのどの位置に属するかを示します。

メッセージボディ情報

  • Content-Length: リソースのサイズ(10進数のバイト数)。
  • Content-Type: リソースのメディアタイプを示します
  • Content-Encoding: 圧縮アルゴリズムを指定するために使われます
  • Content-Language: 対象読者のために意図された人間の言語を記述し、ユーザが好みの言語で区別できるようにします
  • Content-Location: 返されるデータの代替ロケーションを示します

pentest の観点から見ると、この情報は通常は「無意味」ですが、リソースが 401 や 403 で保護されていて、何らかの方法でこの情報を取得できる場合は興味深いことがあります。
例えば、HEAD リクエストでの RangeEtag の組み合わせはページの内容を 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 ヘッダは、ファイルをページ内で表示する(inline)か、添付ファイルとして扱ってダウンロードさせるか(attachment)を指示します。例えば:
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 タイプのスニッフィングを防ぎます。これは XSS 脆弱性につながる可能性がある挙動です。サーバーが指定した MIME タイプをブラウザが尊重するようにします。

X-Content-Type-Options: nosniff

X-Frame-Options

clickjackingを防ぐため、このヘッダーはドキュメントが <frame>, <iframe>, <embed>, または <object> タグに埋め込まれる方法を制限し、すべてのドキュメントが埋め込み許可を明示的に指定することを推奨します。

X-Frame-Options: DENY

Cross-Origin Resource Policy (CORP) と Cross-Origin Resource Sharing (CORS)

CORPは、どのリソースがウェブサイトに読み込まれるかを指定する上で重要で、クロスサイト leaks を軽減します。 CORSは一方で、より柔軟な cross-origin resource sharing メカニズムを提供し、特定の条件下で 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 のような攻撃のリスクを大幅に低減します。これらはそれぞれ、クロスオリジンリソースの読み込みとクロスオリジンウィンドウとの相互作用を制御します。

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 (旧 Feature-Policy)

Permissions-Policy は、ウェブ開発者がドキュメント内の特定のブラウザ機能や API の挙動を選択的に有効化、無効化、または変更できるようにする仕組みです。これは現在非推奨となっている Feature-Policy ヘッダの後継です。悪用される可能性のある強力な機能へのアクセスを制限することで、攻撃対象を減らすのに役立ちます。

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

一般的なディレクティブ:

Directive説明
accelerometer加速度計センサーへのアクセスを制御します
cameraビデオ入力デバイス(ウェブカメラ)へのアクセスを制御します
geolocation位置情報 API へのアクセスを制御します
gyroscopeジャイロスコープセンサーへのアクセスを制御します
magnetometer磁力計センサーへのアクセスを制御します
microphone音声入力デバイスへのアクセスを制御します
paymentPayment Request API へのアクセスを制御します
usbWebUSB API へのアクセスを制御します
fullscreenFullscreen API へのアクセスを制御します
autoplayメディアの自動再生を許可するかどうかを制御します
clipboard-readクリップボードの読み取りアクセスを制御します
clipboard-writeクリップボードへの書き込みアクセスを制御します

構文の値:

  • () - 機能を完全に無効化します
  • (self) - 同一オリジンでのみ機能を許可します
  • * - すべてのオリジンで機能を許可します
  • (self "https://example.com") - 同一オリジンと指定したドメインを許可します

Example configurations:

# 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")

セキュリティの観点から、Permissions-Policy ヘッダーが欠如している、または過度に許容的であると、攻撃者(例:XSS や埋め込み iframe を介して)が強力なブラウザ機能を悪用できる可能性があります。アプリケーションに必要な最小限の機能に常に制限してください。

ヘッダー名の大文字小文字によるバイパス

HTTP/1.1 はヘッダフィールド名を case-insensitive(大文字小文字を区別しない)と定義しています (RFC 9110 §5.1)。それにもかかわらず、カスタムミドルウェア、セキュリティフィルタ、またはビジネスロジックが、受信したヘッダー名をまず大文字小文字を正規化せずに リテラル 比較する(例:header.equals("CamelExecCommandExecutable"))ことは非常に一般的です。これらのチェックが case-sensitively(大文字小文字を区別して)行われている場合、攻撃者は単に異なる大文字小文字で同じヘッダーを送ることでそれらを回避できる可能性があります。

このミスが発生しやすい典型的な状況:

  • リクエストが機密コンポーネントに到達する前に「危険な」内部ヘッダーをブロックしようとするカスタムの許可/拒否リスト。
  • reverse-proxy の疑似ヘッダーの社内実装(例:X-Forwarded-For のサニタイズ)。
  • 管理/デバッグ用エンドポイントを公開し、認証やコマンド選択のためにヘッダー名に依存するフレームワーク。

バイパスの悪用

  1. サーバー側でフィルタリングまたは検証されているヘッダーを特定する(例:ソースコード、ドキュメント、エラーメッセージを読むなど)。
  2. 同じヘッダーを異なる大文字小文字で送信する(混合ケースまたは全大文字)。HTTP スタックは通常ヘッダーをユーザーコード実行の後に正規化するため、脆弱なチェックを回避できる場合があります。
  3. 下流コンポーネントがヘッダーを大文字小文字を区別しない方法で扱う場合(ほとんどがそうです)、攻撃者制御の値を受け入れてしまいます。

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

脆弱なバージョンの Apache Camel では、Command Center ルートが CamelExecCommandExecutableCamelExecCommandArgs ヘッダーを削除することで信頼されていないリクエストをブロックしようとしました。比較は equals() で行われていたため、正確に一致する小文字の名前のみが削除されました。

# 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 process の権限で remote command execution が発生します。

Detection & Mitigation

  • すべてのヘッダー名を単一のケース(通常は小文字)に正規化し、allow/deny 比較を行う前に実施する。
  • 疑わしい重複を拒否する: Header:HeAdEr: の両方が存在する場合、異常として扱う。
  • 正の allow-list を正規化(canonicalisation)に強制的に適用する。
  • 管理用エンドポイントを認証とネットワーク分割で保護する。

References

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をサポートする