コンテンツにスキップ

IP アドレス

IP アドレスは HTTP において基本的な役割を持ち、アクセス制御、監査、地理ベースの分析などに 使われます。Echo はそれを取得するために Context#RealIP() を提供しています。

実際の クライアント IP を取得するのは簡単ではありません。特に L7 プロキシが アプリケーションの前にある場合はそうです。その場合、実際の IP はプロキシから HTTP 経由でアプリへ伝えられる必要があります。ただし HTTP header を無条件に信頼してはいけません。 だまされる可能性があります。これはセキュリティリスクです。

IP を信頼性高く安全に取得するには、アプリケーションがインフラ全体を把握している必要があります。 Echo では Echo#IPExtractor でこれを設定します。

適切な方法を見つけるため、まず 2 つの質問から始めます。

  1. アプリケーションの前に HTTP(L7)プロキシを置いていますか?これにはクラウドの ロードバランサー(AWS ALB や GCP HTTP LB など)や、オープンソースプロキシ (Nginx、Envoy、Istio ingress gateway など)が含まれます。
  2. そうであれば、プロキシはどの HTTP header を使ってクライアント IP をアプリケーションへ渡していますか?

プロキシがない場合(アプリがインターネットに直接向いている場合)、信頼できる唯一のアドレスは ネットワーク層から得られるものです。クライアントが完全に制御できるため、すべての HTTP header は 信頼できません。

echo.ExtractIPDirect() を使います。

e.IPExtractor = echo.ExtractIPDirect()

ケース 2:X-Forwarded-For header を使うプロキシ

Section titled “ケース 2:X-Forwarded-For header を使うプロキシ”

X-Forwarded-For (XFF) は、クライアント IP を中継するもっとも一般的な header です。各ホップで、プロキシは リクエスト IP を header の末尾に追加します。

┌──────────┐ ┌──────────┐ ┌──────────┐
───────────>│ Proxy 1 │───────────>│ Proxy 2 │───────────>│ Your app │
│ (IP: b) │ │ (IP: c) │ │ │
└──────────┘ └──────────┘ └──────────┘
Case 1.
XFF: "" "a" "a, b"
~~~~~~
Case 2.
XFF: "x" "x, a" "x, a, b"
~~~~~~~~~
↑ What your app will see

この場合、右から見て最初の信頼できない IP 読み取り値を使います。左端の最初の値は、 クライアントが制御するため絶対に使わないでください。ここで「信頼できる」とは、その IP が 自分のインフラに属していると確信できることです。上の例では bc が信頼できるなら、 どちらのケースでもクライアント IP は a であり、x ではありません。

ExtractIPFromXFFHeader(...TrustOption) を使います。

e.IPExtractor = echo.ExtractIPFromXFFHeader()

デフォルトでは、loopback、link-local unicast、private-use、 RFC 6890RFC 4291RFC 4193 の unique local アドレスなど、 内部 IP アドレスを信頼します。これは TrustOption で制御できます。

e.IPExtractor = echo.ExtractIPFromXFFHeader(
echo.TrustLoopback(false), // e.g. IPv4 starting with 127.
echo.TrustLinkLocal(false), // e.g. IPv4 starting with 169.254.
echo.TrustPrivateNet(false), // e.g. IPv4 starting with 10. or 192.168.
echo.TrustIPRange(lbIPRange),
)

ケース 3:X-Real-IP header を使うプロキシ

Section titled “ケース 3:X-Real-IP header を使うプロキシ”

X-Real-IP はクライアント IP を中継するもう 1 つの header ですが、XFF と異なり 単一のアドレスだけを保持します。

プロキシがこの header を設定している場合は、ExtractIPFromRealIPHeader(...TrustOption) を使います。

e.IPExtractor = echo.ExtractIPFromRealIPHeader()

XFF と同様に、デフォルトでは内部 IP アドレスを信頼し、同じ TrustOption を受け付けます。

デフォルトでは、Echo は最初の XFF header、X-Real-IP header、ネットワーク層の IP を同時に考慮します。

この記事から分かるように、これは良い選択ではありません。後方互換性のためだけにデフォルトとして残されています。