IP アドレス
IP アドレスは HTTP において基本的な役割を持ち、アクセス制御、監査、地理ベースの分析などに
使われます。Echo はそれを取得するために Context#RealIP() を提供しています。
実際の クライアント IP を取得するのは簡単ではありません。特に L7 プロキシが アプリケーションの前にある場合はそうです。その場合、実際の IP はプロキシから HTTP 経由でアプリへ伝えられる必要があります。ただし HTTP header を無条件に信頼してはいけません。 だまされる可能性があります。これはセキュリティリスクです。
IP を信頼性高く安全に取得するには、アプリケーションがインフラ全体を把握している必要があります。
Echo では Echo#IPExtractor でこれを設定します。
適切な方法を見つけるため、まず 2 つの質問から始めます。
- アプリケーションの前に HTTP(L7)プロキシを置いていますか?これにはクラウドの ロードバランサー(AWS ALB や GCP HTTP LB など)や、オープンソースプロキシ (Nginx、Envoy、Istio ingress gateway など)が含まれます。
- そうであれば、プロキシはどの HTTP header を使ってクライアント IP をアプリケーションへ渡していますか?
ケース 1:プロキシなし
Section titled “ケース 1:プロキシなし”プロキシがない場合(アプリがインターネットに直接向いている場合)、信頼できる唯一のアドレスは ネットワーク層から得られるものです。クライアントが完全に制御できるため、すべての 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 が
自分のインフラに属していると確信できることです。上の例では b と c が信頼できるなら、
どちらのケースでもクライアント IP は a であり、x ではありません。
ExtractIPFromXFFHeader(...TrustOption) を使います。
e.IPExtractor = echo.ExtractIPFromXFFHeader()デフォルトでは、loopback、link-local unicast、private-use、
RFC 6890、
RFC 4291、
RFC 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 を受け付けます。
デフォルトの挙動
Section titled “デフォルトの挙動”デフォルトでは、Echo は最初の XFF header、X-Real-IP header、ネットワーク層の IP を同時に考慮します。
この記事から分かるように、これは良い選択ではありません。後方互換性のためだけにデフォルトとして残されています。