InstaTunnel
Navigation menu o kirikae
Tutorial
10 min read
25 views

転送ヘッダは信頼できない入力です: X-Forwarded-For、Proto、トンネルの背後にある Host

トンネルの背後では、X-Forwarded-For、Proto、そして Host は信頼できない入力です。Express、Fastify、Django、Rails に適した trustProxy の設定を学びましょう。

IT
InstaTunnel Team
Published by the InstaTunnel team | Editorial policy
転送ヘッダは信頼できない入力です: X-Forwarded-For、Proto、トンネルの背後にある Host

Quick answer

トンネル背後の転送ヘッダは信頼できない入力: quick answer

If free tunnel limits interrupt your workflow, compare session length, stable URLs, concurrent tunnels, and paid-plan pricing before choosing a localhost tunnel tool.

What free tunnel limits should developers check first?

Check session duration, URL stability, concurrent tunnels, custom subdomains, bandwidth or request limits, and whether webhook callbacks survive restarts.

How does InstaTunnel handle longer development sessions?

InstaTunnel Free is designed around 24-hour sessions, with Pro available for higher limits and MCP endpoint tunnel workflows.

アプリをトンネルの背後に置くと、3つのリクエストヘッダがコードが信じる値を決定し始めます。X-Forwarded-For は誰が呼び出しているかを示し、X-Forwarded-Proto はリクエストが HTTPS かどうかを示し、X-Forwarded-Host は呼び出し元が要求したホスト名を示します。設定を誤って trustProxy の設定をすると、2つの障害のいずれかが発生します。無害な方はリダイレクトループや、単一の訪問者を検知するレートリミッターです。有害な方は、攻撃者がセキュリティチェックの依存値を選択する場合です。

2026年は2つ目の障害を具体化しました。Fastify はこの問題で5か月の間に2つの CVE を公開し、Express の req.ip の背後にある proxy-addr パッケージにも信頼サブネットの重大なバグがありました。本ガイドでは、トンネルが実際に送るもの、アプリがなぜ誤読するのか、Express、Fastify、Django、Rails で機能する設定を解説します。

トンネルが実際に送るもの

トンネルは接続の形を変えます。訪問者の TLS セッションはプロバイダーのエッジで終了します。エッジはトンネルを介してあなたのマシン上のエージェントへリクエストを転送し、エージェントはローカルホスト上のあなたのアプリへプレーン HTTP リクエストを送ります。あなたのアプリは決して訪問者のソケットを見ません。見える接続はエージェントから来たもので、通常は 127.0.0.1、訪問者のその他の情報はすべてヘッダとして到着します。

プロバイダのドキュメントにはこれらのヘッダが説明されています:

  • ngrok は X-Forwarded-For にクライアントIPを、X-Forwarded-Proto にリクエストスキームを追加します。訪問者がすでにいずれかのヘッダを送信している場合、ngrok は旧値を置換せず新しい値を追加します。X-Forwarded-Host については、訪問者のヘッダが存在する場合は保持し、そうでなければリクエストの Host を使用します。
  • Cloudflare は訪問者のアドレスを CF-Connecting-IP で送信し、X-Forwarded-For よりも推奨します。既存の X-Forwarded-For がある場合は接続先アドレスを追加するため、訪問者が入力した値は左側に残ります。公開の cloudflared の問題は、偽造されたリストを伴うリクエストが本来のアドレスを末尾に追加して origin に到着するケースを示しています。

どこでも同じパターンです:エッジは追加しますが、サニタイズはしません。訪問者が入力したものは、あなたのアプリが受け取るヘッダに依然として残っています。信じられるのは、あなたが管理するホップによって追加されたエントリだけです。

なぜレートリミッターはトンネルのIPを認識するのか

多くのレートリミッターはソケットアドレスをキーにします。トンネルの背後では、すべてのリクエストが localhost のエージェントから来るため、すべての訪問者が同じバケットに入ります。

1つの騒がしいクライアントが全員のクォータを使い果たしてしまい、IP許可リストは全てのトラフィックをブロックするか、すべてを許可するかのどちらかになります。

対策は、接続元アドレスが信頼できるプロキシであることをフレームワークに伝え、X-Forwarded-For からクライアントアドレスを安全に読み取れるようにすることです。誤った対策は、ヘッダの最初の値を自分で読んでしまうことです。MDN の指針は明確です:レート制限や IP アクセス制御など、X-Forwarded-For のセキュリティ用途は、信頼されたプロキシが追加したアドレスのみを使用すべきで、左端の値は偽装が影響を与えない場合にのみ適用されます。Go の問題ではレートリミッターを調査したところ同じ誤りが繰り返され、左端の解析によりクライアントが制限を回避していました。

なぜ間違ったプロトコル検出がリダイレクトループを引き起こすのか

TLS はエッジで終了するため、アプリはプレーン HTTP を受け取ります。HTTPS を強制すると、不安全なリクエストとして扱われ、https:// へのリダイレクトで応答します。ブラウザはそれに従い、リクエストは再びエッジを通過し、あなたのアプリは再びプレーン HTTP を受け取ります。ループは終わりません。

Django のドキュメントはこれを直接述べています:SECURE_SSL_REDIRECT が無限リダイレクトを引き起こす場合、サイトはおそらくプロキシの背後でどのリクエストが安全かを識別できず、SECURE_PROXY_SSL_HEADER が対策です。Rails も同じ罠を説明しており、SSL 終端のプロキシの背後では転送されたリクエストが HTTP のように見え、リダイレクトとクッキーのセキュリティが誤ったスキームへ送られることを指摘しています。

設定を変更する前に、実際に到着する値を出力してください。2024年のある記事では、X-Forwarded-Proto が Cloudflare Tunnel を通じて http のままで、代わりに CF-Visitor ヘッダを使用していたと報告しています。提供者が挙動を変更することがあるため、必ず自分のリクエストで検証してください。

ルール: 接続を信頼してからヘッダを信頼する

X-Forwarded-* ヘッダは主張であり、事実ではありません。MDN は、サーバーがインターネットから直接到達可能であっても、信頼されたプロキシの背後にある場合には、X-Forwarded-For のリストのいかなる部分も信頼できないと述べています。安全なアルゴリズムには2つのステップがあります:

  1. 接続元アドレスが信頼できるプロキシに属しているかを確認します。
  2. その後に右側のヘッダを読んで、信頼済みプロキシをスキップします。最初の信頼されていないアドレスがクライアントです。

ステップ1をスキップする、または不適切に実装するフレームワークは、2026年の警告の原因となったものです。

2026年の CVE の追跡

CVE-2026-3635 (Fastify、2026年3月23日公開)。 Fastify 5.8.2 およびそれ以前では、1 IP、サブネット、ホップ数、またはカスタム関数のような制限的な trustProxy 値でも、request.protocol と request.host が、信頼できない接続を含む任意の接続から X-Forwarded-Proto と X-Forwarded-Host を読み取ることを許していました。攻撃者がサーバへ直接到達することで両方を偽装できました。勧告は HTTPS の強制、セキュア クッキー フラグ、CSRF の発信元チェック、URL の構築、ホストベースのルーティングを影響として挙げています。CVSS スコアは 6.1、修正は Fastify 5.8.3。trustProxy: true の場合、すべてを信頼する設定のため挙動は予想通りです。

CVE-2026-16732 (Fastify、2026年8月18日公開)。 5.8.3 のガードは接続元アドレスを読み取りますが、IP、CIDR、関数形式のいずれにも対応します。数値のホップカウント形式は、アドレスを無視する述語へ変換されるため、ガードは常に通過します。バージョン 5.8.3 から 5.12.1 まで脆弱性が残り、影響は親 CVE と一致し、キャッシュポイズニングを追加します。Fastify 5.12.1 は実行時に数値の trustProxy を無効化し、TypeScript の型からも削除します。勧告の回避策は IP、CIDR、関数値のいずれかと、元のアドレスがプロキシチェーンを介してのみ到達可能であることを確実にすることです。

CVE-2026-90711 (proxy-addr、2026年9月15日公開)。 proxy-addr は信頼済みプロキシの背後にあるクライアントアドレスを決定し、Express の req.ip および req.ips を支えます。バージョン 1.1.0 から 2.0.7 では、IPv4 相当のプレフィックスを持つ IPv4 マッピング IPv6 形式の信頼サブネット、たとえば ::ffff:10.0.0.0/8 が受け入れられ、任意の IPv4 アドレスを信頼してしまいました。これにより、任意のクライアントが任意の X-Forwarded-For を提供でき、IP アクセス制御、レートリミット、ジオロケーション、監査ログを回避します。CVSS スコアは 9.1、修正は 2.0.8。Fastify のプラグインはこれを CVE-2026-92395 として継承し、@fastify/proxy-addr 3.0.0 から 5.1.0 に影響、5.1.1 で修正されました。

勧告は共通の前提条件を共有します。攻撃者はプロキシを経由せずにアプリに到達する必要があります。トンネルでは、それは現実的でないように聞こえますが、あなたの開発サーバの束縛方法を確認してください。0.0.0.0 をリッスンしているサーバ、または公開ポートを持つコンテナは、トンネルなしで LAN から到達可能です。これはバインディングの仕組みからの推測であり、勧告が述べていることではありませんが、「開発用トンネルだけ」という言い訳が弱い理由になることを説明します。127.0.0.1 にバインドしてください。

フレームワーク別の正しい信頼設定

Express

Express はデフォルトで trust proxy を false に設定しているため、req.ip はソケットアドレスとなり、すべての訪問者がエージェントのように見えます。これを true に設定すると、それを修正する代わりに別の問題が生じます。つまり、左端の X-Forwarded-For エントリをクライアントとして扱い、最後の信頼済みプロキシが転送ヘッダを上書きする必要があると警告します。トンネルがヘッダを追加するため、true は誤った選択です。

エージェントのアドレスを代わりに信頼してください:

// Agent runs on the same machine
app.set('trust proxy', 'loopback');

// Agent in a container: trust that network only
app.set('trust proxy', ['loopback', '172.18.0.0/16']);

Express は、ソケットのピアが信頼されている場合にのみ右から X-Forwarded-For を読むようにします。この設定では、req.protocol は X-Forwarded-Proto、req.hostname は X-Forwarded-Host に従い、req.ip は右端から最初の信頼されていないアドレスになります。proxy-addr を 2.0.8 以降にアップグレードし(npm ls proxy-addr で現在のコピーを確認)、IPv4 マッピングされた IPv6 サブネットを二重に確認してください。

Fastify

5.12.1 以降へアップグレードし、数値で表現する値の使用を止めてください:

const fastify = require('fastify')({
  trustProxy: ['127.0.0.1', '::1'] // IPs or CIDRs of the agent only
});

Fastify の現在のドキュメントも request.ip、request.host、request.protocol を信頼できない入力として扱うメタデータを示しています。チェックが回避されないよう、サーバをループバックにバインドしてください。

Django

Django にはクライアント IP の trust proxy 相当はありません。REMOTE_ADDR はソケットのピアであるため、意図的な選択が必要です。スキームには以下の2つの設定が重要です:

# settings.py
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SECURE_SSL_REDIRECT = True

Django 自身の警告はこうです:この設定は、プロキシが受信リクエストから X-Forwarded-Proto を取り除く場合にのみ適用してください。トンネルがヘッダを追加するだけで上書きしない場合はこの条件を満たしません。サーバーレイヤーでは、gunicorn はデフォルトで 127.0.0.1 からの転送ヘッダのみを信頼します(forwarded_allow_ips)。uvicorn の --proxy-headers はデフォルトでオンですが、--forwarded-allow-ips に限定され、デフォルトは 127.0.0.1 です。コンテナの設定では * を設定しがちですが、エージェントのネットワークを列挙してください。クライアント IP には django-ipware が proxy_trusted_ips と proxy_count をサポートしています。

Rails

ActionDispatch::RemoteIp は転送チェーンから信頼済みプロキシを削除し、残った最後のアドレスを返します。デフォルトの信頼済みリストはループバックとプライベートレンジをカバーしており、localhost のトンネルエージェントに適しています。また、Client-Ip と X-Forwarded-For が矛盾した場合は IpSpoofAttackError を発生させます。config.action_dispatch.trusted_proxies を設定する場合は、デフォルトを置換する配列を渡してください。

リダイレクトループを回避するには、Rails は config.assume_ssl = true を提供します。これはサーバに対し、プロキシがすでに SSL を終了したと伝えるものです。トンネルを通じてのみアプリにアクセスできる場合に限り使用してください。この設定はすべてのリクエストを HTTPS とみなします。

攻撃者のようにテストする

トンネルを介さずにローカルポートへ偽造ヘッダを直接送信します:

curl -s http://127.0.0.1:3000/debug \
  -H 'X-Forwarded-For: 203.0.113.9' \
  -H 'X-Forwarded-Proto: https' \
  -H 'X-Forwarded-Host: evil.example'

正しく設定された場合、ソケットアドレスをクライアントとして、プレーン HTTP、そして実際のホストが表示されます。これは接続元アドレスが信頼できるプロキシではなかったためです。次に、同じルートをトンネル経由で偽造した X-Forwarded-For でリクエストし、エッジで追加されたアドレスが報告され、偽造された値ではないことを確認します。すべての環境で両方のチェックを実行してください。ステージングは本番設定を別のプロキシ向けに継承していることがよくあるためです。

エッジを Traffic Policies で活用する

アプリケーション設定はあなたの最後の防御線です。エッジは実際の TCP 接続を見ているため、エッジのルールはヘッダの信頼に依存しません。Traffic Policies は、アプリの前に置くべきです。3つの役割があります:

  • ヘッダルール. クライアントが提供する X-Forwarded-* ヘッダを上書きまたは削除し、アプリにはエッジが設定した値のみが見えるようにします。
  • IP ルール. 実際の接続アドレスで訪問者を許可またはブロックします。
  • IP でキー付けされたレート制限. 各訪問者を個別に制限します。1人のノイジーなクライアントが全員のクォータを使い果たさないようにするためで、これはまさにあなたのアプリがエージェントのアドレスをキーにする時に起こることです。

エッジルールとフレームワーク設定はお互いを補完します。もし誤設定された trustProxy が一度でも紛れ込んだ場合でも、エッジはヘッダをすでに正規化し、実際のアドレスに対して制限を適用しています。

よくある質問

X-Forwarded-For をレート制限に安全に使えますか? 信頼できるプロキシが追加したエントリだけです。右からヘッダを読み、信頼済みプロキシをスキップして、左端の値を訪問者が操作した値として扱います。

なぜトンネルを介してのみリダイレクトループになるのですか? TLS がエッジで終了するため、アプリはプレーン HTTP を見ることになります。 proxy が信頼性をもって設定するヘッダから転送スキームを読めるよう、フレームワークを設定してください。

trust proxy: true を使うべきですか? ヘッダを追加するトンネルの背後では避けてください。エージェントのアドレスを信頼してください。

数値ベースの信頼値は安全ですか? Fastify では 5.12.1 まで無効化されていませんでしたが、現在は推奨されません。明示的なアドレスをすべての場所で優先してください。

これはローカル開発のみに影響しますか? いいえ。本番環境でも、任意のプロキシやロードバランサーの背後で同じ信頼モデルが適用されます。

出典

Continue from this article into the most relevant product guides and workflows.

Related Topics

#x-forwarded-for#x-forwarded-proto#x-forwarded-host#forwarded headers#forwarded header security#trust proxy#trustProxy#trust proxy settings#trust proxy Express#trust proxy Fastify#Fastify trustProxy#Django SECURE_PROXY_SSL_HEADER#Rails trusted proxies#Express behind proxy#header spoofing#IP spoofing#client IP spoofing#host header spoofing#protocol spoofing#X-Forwarded-For spoofing#CVE-2026-3635#CVE-2026-16732#Fastify CVE#Fastify vulnerability#proxy-addr vulnerability#proxy-addr#HTTPS enforcement bypass#secure cookie bypass#secure cookies behind proxy#redirect loop HTTPS#infinite redirect loop#wrong protocol detection#req.ip behind proxy#real client IP#get client IP behind proxy#rate limiting by IP#rate limiter tunnel IP#IP allowlist#IP-based access control#tunnel security#localhost tunnel#localhost tunneling#ngrok alternative#reverse proxy security#reverse proxy headers#proxy headers#web application security#application security#AppSec#secure web development#DevSecOps#DevOps security#Node.js security#Python Django security#Ruby on Rails security#developer infrastructure#cloud-native security#traffic policies#header rules#webhook testing

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles