
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 であることを意味します。
ここでの「ビューワー」とは、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 は偽装可能です。
クライアントもしくはプロキシーに悪意がある、または設定ミスがある場合、ヘッダーの一部(もしくは全て)がなりすましの可能性があります。
偽装された場合、左端が偽装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-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/