見出し画像

CloudFront + ALB環境に構築した Spring Boot でクライアントIP を取得する


はじめに


はじめまして。株式会社SHIFT アプリケーション開発テクノロジーグループ の福士です。
CloudFront + ALB環境に構築した Spring Boot で、クライアントIP を取得する方法と注意すべきポイントをまとめてみましたので、ご紹介します。

環境


  • (AWS) Amazon CloudFront

  • (AWS) ALB

  • Spring Boot 2.7

課題


Java でクライアントIP を取得する場合、HttpServletRequest の getRemoteAddr を利用する方法が一般的です。

String addr = request.getRemoteAddr();

しかし、正確には getRemoteAddr で取得する IP は、リクエスト元の IP です。

クライアントとアプリケーションサーバーの間にリバースプロキシやプロキシサーバーなどを介したリクエストにおいては、getRemoteAddr の取得値が、リクエスト元であるリバースプロキシ/プロキシサーバーの IP になってしまいます。

今回の環境は、ユーザーとアプリケーションサーバーの間に ALB(リバースプロキシ)があるので、getRemoteAddr の取得値は ALB の IP です。

結論:CloudFront-Viewer-Address ヘッダーを利用する


CloudFront + ALB + Spring Boot の環境では、 CloudFront-Viewer-Address ヘッダーを利用する方法がスマートです。

CloudFront-Viewer-Address とは

CloudFront ではオリジンに転送するリクエストに任意のリクエストヘッダーを追加できます。

CloudFront-Viewer-Address – ビューワーの IP アドレスと、リクエストのソースポートを示します。例えば、198.51.100.10:46532 のヘッダー値は、ビューワーの IP アドレスが 198.51.100.10 で、リクエストのソースポートが 46532 であることを意味します。

引用元: CloudFront のリクエストヘッダーを追加する(Amazon CloudFront 開発者ガイド)

ここでの「ビューワー」とは、Webアプリケーションにアクセスするクライアントを指します。

CloudFront で設定後、アプリケーションサーバーで CloudFront-Viewer-Address を参照することで、クライアントIP を取得することが可能です。

CloudFront の設定方法

オリジンリクエストポリシーを作成する(Amazon CloudFront 開発者ガイド) をご参照ください。
「CloudFront > ポリシー > オリジンリクエスト > オリジンリクエストポリシーを作成」 から設定できます。

Spring Boot での取得方法

HttpServletRequest からヘッダー指定で取得します。

String addr = request.getHeader("CloudFront-Viewer-Address");

取得形式

取得形式は [IP] + ": (セミコロン)" + [ポート番号] です。IPv4、IPv6 のいずれかの形式で取得します。

# IP: nnn.nnn.nnn.nnn(IPv4) / port: 1111 の場合
CloudFront-Viewer-Address: nnn.nnn.nnn.nnn:1111

# IP: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx(IPv6) / port: 1111 の場合
CloudFront-Viewer-Address: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:1111

補足:X-Forwarded-For ヘッダーについて


X-Forwarded-For ヘッダーからもクライアントIP を取得できますが、取り扱いには注意が必要です。

X-Forwarded-For とは

クライアントIP や、クライアントとアプリケーションサーバー間にあるリバースプロキシやプロキシサーバーの IP を格納したヘッダーです。
取得形式はカンマ区切りで、通常、左端(<client>)がクライアントIP です。

X-Forwarded-For: <client>, <proxy1>, <proxy2>

X-Forwarded-For は偽装できる

X-Forwarded-For は偽装可能です。

クライアントもしくはプロキシーに悪意がある、または設定ミスがある場合、ヘッダーの一部(もしくは全て)がなりすましの可能性があります。

引用元: X-Forwarded-For(MDN Web Docs)

偽装された場合、左端が偽装IP で格納されるため、正しいクライアントIP を取得することが困難になります。

X-Forwarded-For: <偽装IP>, <client>, <proxy1>, <proxy2>

正しくクライアントIP を取得するには

ここでは割愛しますが、アプリケーションサーバーで取得した X-Forwarded-For に対して、リバースプロキシ/プロキシサーバーの IP(信頼できる IP)を除外する処理を行うことで、X-Forwarded-For の右端からクライアントIP を取得できます。

ただし、CloudFront のように IP範囲自体が変わる可能性のあるリバースプロキシの場合は、その都度、最新の信頼できる IP範囲を API などで取りに行く必要があるので、注意が必要です。

専用 IP は静的 IP ではないため、時間の経過とともに変化する可能性があります。エッジロケーションに返される IP アドレスは、CloudFront エッジサーバーリスト の IP アドレス範囲から動的に割り当てられます。
CloudFront エッジサーバーの IP アドレス範囲は、変わる可能性があります。IP アドレスの変更に関する通知を受け取るには、Amazon SNS 経由で AWS パブリック IP アドレスの変更をサブスクライブします。

引用元: CloudFront で HTTPS リクエストを処理する方法を選択する(Amazon CloudFront 開発者ガイド)

おわりに


CloudFront-Viewer-Address ヘッダーによるクライアントIP の取得方法のご紹介でした。クライアントIP をよりシンプルに取得することができますので、ぜひ活用してみてください。

最後までお読みいただきありがとうございました。


執筆者プロフィール:福士
SHIFT アプリケーション開発テクノロジーグループ所属の開発エンジニアです。

SHIFTへのお問合せはお気軽に

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/

PHOTO:UnsplashJJ Ying