要望や症状
AWS CloudFrontやロードバランサー、クラウド型WAFを使用している環境において、EC-CUBEのログ記録で問題が発生することがあります。
具体的には、/var/log配下のシステムログに実際のアクセス元IPアドレスではなく、CloudFrontのIPアドレスが記録されてしまいます。また、管理画面のログイン履歴においても、本来のアクセス元IPアドレスではなく中間プロキシのIPアドレスが記録される場合があります。この現象は、AWS CloudFront、ロードバランサー、クラウド型WAF等のプロキシを経由してアクセスが行われる環境で顕著に現れます。
理由や原因
この問題の根本的な原因は、EC-CUBEのログ機能におけるIPアドレスの取得方法がX-Forwarded-Forヘッダーを適切に参照していないことにあります。
EC-CUBEでは、管理画面のログイン履歴とシステムログでIPアドレスの取得方法が異なっています。管理画面のログイン履歴ではX-Forwarded-Forヘッダーを参照してIPアドレスを取得する一方で、/var/log配下のシステムログではREMOTE_ADDRを使用してIPアドレスを記録しています。
プロキシを経由したアクセスの場合、REMOTE_ADDRにはプロキシサーバーのIPアドレスが設定され、実際のクライアントIPアドレスはX-Forwarded-Forヘッダーに含まれることになります。この仕様の不統一により、システムログでは実際のアクセス元IPアドレスが正しく記録されない状態となっています。
解決策
システムログにおけるIPアドレス記録を正しく動作させるためには、以下のカスタマイズを実装してください。
イベントリスナーの作成
最初に、app/Customize/EventListener/LogIpAddressListener.phpを作成します。このファイルでは、リクエスト処理の早い段階でX-Forwarded-Forヘッダーから実際のクライアントIPアドレスを取得し、REMOTE_ADDRを適切な値に更新します。
<?php
namespace Customize\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LogIpAddressListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 10]
];
}
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
// X-Forwarded-ForヘッダーからクライアントIPを取得
$forwardedFor = $request->headers->get('X-Forwarded-For');
if ($forwardedFor) {
$ips = explode(',', $forwardedFor);
$clientIp = trim($ips[0]);
// REMOTE_ADDRを上書き
$request->server->set('REMOTE_ADDR', $clientIp);
}
}
}
サービス設定の追加
次に、作成したイベントリスナーをSymfonyのサービスコンテナに登録します。app/Customize/Resource/config/services.yamlに以下の設定を追加してください。
services:
Customize\EventListener\LogIpAddressListener:
tags:
- { name: kernel.event_subscriber }
注意事項
このカスタマイズを実装する際には、いくつかの重要な点を考慮する必要があります。
セキュリティの観点から、X-Forwarded-Forヘッダーは悪意のあるユーザーによって偽装される可能性があるため、信頼できるプロキシからのリクエストのみに適用することを強く推奨します。本カスタマイズは全てのリクエストに影響を与えるため、本番環境に適用する前に十分なテストを実施してください。
また、この問題の根本的な解決については、EC-CUBE本体での対応が検討されており、将来のバージョンアップで解決される可能性があることも付け加えておきます。