16 KiB
特殊なHTTPヘッダー
{{#include ../../banners/hacktricks-training.md}}
ワードリストとツール
- https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers
- https://github.com/rfc-st/humble
ロケーションを変更するヘッダー
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 header は、end-to-end header とは対照的に、リクエストを現在処理している proxy によって処理・消費されることを目的としたヘッダーです。
Connection: close, X-Forwarded-For
{{#ref}} ../../pentesting-web/abusing-hop-by-hop-headers.md {{#endref}}
HTTP Request Smuggling
Content-Length: 30
Transfer-Encoding: chunked
{{#ref}} ../../pentesting-web/http-request-smuggling/ {{#endref}}
Expect ヘッダー
クライアントが Expect: 100-continue
を送信し、サーバーが HTTP/1.1 100 Continue
で応答してクライアントにリクエストボディの送信を続行させるという動作が可能です。しかし、一部の proxy はこのヘッダーを好まない場合があります。
Expect: 100-continue
の興味深い挙動:
- HEAD リクエストにボディを付けて送信したところ、サーバーが HEAD リクエストにはボディがないことを考慮せず、接続をタイムアウトするまで開いたままにした。
- 別のサーバーはレスポンスにソケットから読み取ったランダムなデータや秘密鍵などの奇妙なデータを返したり、フロントエンドがヘッダー値を削除するのを防いだりした。
- バックエンドが 100 ではなく 400 を返したため、
0.CL
desync が発生した。proxy のフロントエンドは当初のリクエストのボディを送る準備をしていたためボディを送信し、バックエンドはそれを新しいリクエストとして扱った。 Expect: y 100-continue
のバリエーションを送ることでも0.CL
desync を引き起こした。- バックエンドが 404 を返した類似のエラーは
CL.0
desync を発生させた。悪意あるリクエストがContent-Length
を示すため、バックエンドは悪意あるリクエスト本体に加え次のリクエスト(被害者)のContent-Length
バイトを読み込む。これによりキューがずれて、バックエンドは悪意あるリクエストに対して 404 を返しつつ被害者のレスポンスも返すが、フロントエンドは一つのリクエストしか送信されていないと思い、二番目のレスポンスを別の被害者リクエストへ送ってしまい、以降もずれていく。
HTTP Request Smuggling の詳細は以下を参照してください:
{{#ref}} ../../pentesting-web/http-request-smuggling/ {{#endref}}
キャッシュヘッダー
サーバー側のキャッシュヘッダー:
X-Cache
: レスポンス内でリクエストがキャッシュされていない場合はmiss
、キャッシュされている場合はhit
の値を持つことがある。- 同様の挙動は
Cf-Cache-Status
ヘッダーにも見られる。 Cache-Control
はリソースがキャッシュされるかどうか、および次にいつキャッシュが有効かを示す:Cache-Control: public, max-age=1800
Vary
はレスポンスで、通常はキャッシュキーに含まれないヘッダーでもキャッシュキーの一部として扱われる追加のヘッダーを示すためによく使われる。Age
はオブジェクトが proxy キャッシュに存在していた時間を秒単位で示す。Server-Timing: cdn-cache; desc=HIT
もリソースがキャッシュされていたことを示す。
{{#ref}} ../../pentesting-web/cache-deception/ {{#endref}}
ローカルキャッシュヘッダー:
Clear-Site-Data
: 削除すべきキャッシュを示すヘッダー:Clear-Site-Data: "cache", "cookies"
Expires
: レスポンスが期限切れになる日時を含む:Expires: Wed, 21 Oct 2015 07:28:00 GMT
Pragma: no-cache
はCache-Control: no-cache
と同じWarning
: 一般的な HTTP ヘッダーで、メッセージの状態に関する可能性のある問題についての情報を含む。レスポンスに複数のWarning
ヘッダーが含まれることがある。Warning: 110 anderson/1.3.37 "Response is stale"
条件付きリクエスト
If-Modified-Since
とIf-Unmodified-Since
を用いたリクエストは、レスポンスヘッダーLast-Modified
が異なる日時を含む場合にのみデータが返される。If-Match
とIf-None-Match
を用いた条件付きリクエストは Etag 値を使用し、データ(Etag)が変更されていればサーバーはレスポンスの内容を送る。Etag
は HTTP レスポンスから取得される。- Etag 値は通常レスポンスのコンテンツに基づいて計算される。例えば、
ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"
は Etag が 37 バイトの Sha1 であることを示す。
Range リクエスト
Accept-Ranges
: サーバーが範囲リクエストをサポートしているか、およびどの単位で範囲が表現されるかを示す:Accept-Ranges: <range-unit>
Range
: サーバーが返すべきドキュメントの一部を示す。例えば、Range: 80-100
は元のレスポンスのバイト80から100を 206 Partial Content で返す。リクエストからAccept-Encoding
ヘッダーを削除することも忘れないでください。- これは、通常はエスケープされる任意の反射型 JavaScript コードを含むレスポンスを得るのに有用な場合がある。しかしこれを悪用するにはリクエストにこれらのヘッダーを注入する必要がある。
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
ヘッダーは、ファイルをウェブページ内に表示する(inline)か、添付ファイルとして扱ってダウンロードさせる(attachment)かを指示します。例えば:
Content-Disposition: attachment; filename="filename.jpg"
これは "filename.jpg" という名前のファイルがダウンロードされ保存されることを意図していることを意味します。
セキュリティヘッダー
コンテンツセキュリティポリシー (CSP)
{{#ref}} ../../pentesting-web/content-security-policy-csp-bypass/ {{#endref}}
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, '<').replace(/>/g, '>');
});
}
// 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
クロスオリジンリソースポリシー (CORP) と クロスオリジンリソース共有 (CORS)
CORP は、どのリソースがウェブサイトによって読み込まれるかを指定する上で重要であり、cross-site leaks を軽減します。CORS は、一方でより柔軟なクロスオリジンリソース共有の仕組みを提供し、特定の条件下で same-origin policy を緩和します。
Cross-Origin-Resource-Policy: same-origin
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
Cross-Origin Embedder Policy (COEP) と Cross-Origin Opener Policy (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
ヘッダ名の大文字小文字によるバイパス
HTTP/1.1 はヘッダフィールド名を 大文字小文字を区別しない と定義しています (RFC 9110 §5.1)。それにもかかわらず、カスタムミドルウェア、セキュリティフィルタ、ビジネスロジックの中には、受信したヘッダ名を大文字小文字正規化せずにそのまま比較する実装(例: header.equals("CamelExecCommandExecutable")
)がよく見られます。これらのチェックが 大文字小文字を区別して 行われている場合、攻撃者は単に異なる大文字小文字で同じヘッダを送ることでバイパスできる可能性があります。
典型的な発生場面:
- 機密コンポーネントに到達する前に「危険な」内部ヘッダをブロックしようとするカスタムの許可/拒否リスト。
- リバースプロキシの疑似ヘッダを自社実装しているケース(例:
X-Forwarded-For
のサニタイズ)。 - 管理/デバッグ用エンドポイントを公開し、認証やコマンド選択にヘッダ名を利用しているフレームワーク。
バイパスの悪用
- サーバ側でフィルタリングまたは検証されているヘッダを特定する(例: ソースコード、ドキュメント、エラーメッセージを読む)。
- 同じヘッダを異なる大文字小文字で送る(混合ケースや全大文字など)。HTTPスタックは通常ユーザコード実行後にヘッダを正規化するため、脆弱なチェックを回避できることがある。
- 下流のコンポーネントがヘッダを大文字小文字を区別しない方法で扱う(ほとんどはそうする)場合、攻撃者が制御した値を受け入れてしまう。
例: Apache Camel exec
RCE (CVE-2025-27636)
脆弱なバージョンの Apache Camel では、Command Center ルートが信頼できないリクエストをブロックしようとして CamelExecCommandExecutable
と CamelExecCommandArgs
のヘッダを削除していました。比較は 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プロセスの権限でremote command executionが発生します。
検出と緩和
- すべてのヘッダー名を単一のケース(通常は小文字)に正規化し、allow/denyの比較を行う前にこれを実施する。
- 疑わしい重複を拒否する:
Header:
とHeAdEr:
の両方が存在する場合は異常として扱う。 - positive allow-list を canonicalisation の後で適用する。
- 管理用エンドポイントを認証とネットワーク分割で保護する。
References
- CVE-2025-27636 – RCE in Apache Camel via header casing bypass (OffSec blog)
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
- https://web.dev/security-headers/
- https://web.dev/articles/security-headers
{{#include ../../banners/hacktricks-training.md}}