EC-CUBE4.3 .env CDN PHP Symfony セキュリティ リバースプロキシ

X-Forwarded-For(XFF)の先頭に書かれたIPは、リクエストの送信者が自由に書き換えられます。実際のクライアントIPは、自分で管理しているプロキシが付け足した分を右から取り除き、残った一番右の値として決めます。

XFFは右端から順に信用できる

XFFは、プロキシを経由するたびに、そのプロキシが「自分に接続してきた相手のIP」を末尾に付け足していくヘッダーです。クライアント → CDN → ロードバランサー → Webサーバーという構成なら、Webサーバーには次のように届きます。

X-Forwarded-For: 203.0.113.10, 192.0.2.44
(203.0.113.10 = CDNが記録したクライアント、192.0.2.44 = ロードバランサーが記録したCDNのノード)

クライアントは最初のリクエストに好きなXFFヘッダーを付けて送れ、プロキシはそれを消さずに後ろへ付け足すだけです。信用できるのは、自分で管理しているプロキシが書いた右側の値だけです。

判断の手順は次のとおりです。

  1. 自分の構成で、XFFに値を付け足すプロキシがいくつあるかを数える(上の例ならCDNとロードバランサーの2つ)
  2. 右端から、その各プロキシが付け足した値を取り除く
  3. 残った値のうち一番右が、自分のプロキシに接続してきた実際のクライアントIP

先頭が偽装されていたログの実例

EC-CUBEサイトのログを見ていて、カート投入のPOSTを数分で数百回繰り返すbotを見つけました(すべて404で失敗しており、購入は成立していません)。普段のXFFは上の例のように2つの値が並びますが、このbotのリクエストだけは3つ並んでいました。

"198.51.100.7, 203.0.113.10, 192.0.2.44"
"198.51.100.93, 203.0.113.10, 192.0.2.61"
"198.51.100.150, 203.0.113.10, 192.0.2.44"

先頭の値はリクエストごとにバラバラでした。一方、2番目の値はほぼすべて同じ国内のモバイル回線でした。bot自身がXFFヘッダーを付けて先頭に偽のIPを入れ、CDNがその後ろに本当の接続元を付け足していた、ということです。先頭の値で集計すると、数百の別々の相手から少しずつ来たように見え、本当の接続元は上位に出てきません。

ログを見るときは、XFFの値の数が自分の構成より多い行を疑ってください。多い分は送信者が付けた値です。

EC-CUBEではTRUSTED_PROXIESに信用するプロキシを並べる

Symfonyの Request::getClientIp() は、信用するプロキシとして登録したIPを右から取り除き、残った一番右の値を返します。EC-CUBE 4.3の index.php は .env の TRUSTED_PROXIES をカンマで区切って Request::setTrustedProxies() に渡します。初期状態ではコメントアウトされています。

TRUSTED_PROXIES=10.0.0.0/8,192.0.2.0/24

ロードバランサーだけを登録した場合と、CDNも登録した場合で、Symfony 6.4の getClientIp() が何を返すかを実測しました(接続元のロードバランサーは 10.0.0.5)。

信用するプロキシ XFFが2つ(通常) XFFが3つ(先頭が偽装)
未設定 10.0.0.5 10.0.0.5
ロードバランサーのみ 192.0.2.44 192.0.2.44
ロードバランサー+CDN 203.0.113.10 203.0.113.10

どの設定でも、偽装された先頭の 198.51.100.7 は返りません。ただし、正しいクライアントIPが返るのは経由するプロキシをすべて登録したときだけです。ロードバランサーだけを登録するとCDNのノードIPが返るので、アプリのログにはCDNのIPが並びます。未設定なら、すべてのアクセスがロードバランサーのIPから来たように記録されます。

信用リストに入れる範囲の注意

CDNを信用リストに入れるときは、そのCDNが公開している送信元IPの範囲を登録します。範囲は変わることがあるので、定期的に見直してください。

なお、接続元が信用リストに入っていない場合、SymfonyはXFFを読まずに接続元のIPをそのまま返します(上の表の「未設定」の行)。プロキシを経由せずWebサーバーへ直接送られたリクエストは、XFFをどう書いても無視されます。

日本発!ECオープンプラットフォーム「EC-CUBE」 EC-CUBEゴールドパートナー EC-CUBEは株式会社イーシーキューブの商標です

EC-CUBEに関するお問い合わせ


    [重要]現在公式にセキュリティサポートが切れていないPHPは8.1以上、MySQLは8.0以上で、対応しているEC-CUBEバージョンは4.2以上です。古いEC-CUBEを使っている方は適切なタイミングでバージョンアップをご検討ください。

    EC-CUBEバージョンアップ