要望や症状
ロードバランサー配下にEC-CUBEサーバを構築している環境で、管理画面IP制限設定を実施しようとすると、すべてロードバランサーのIPで制限がかかってしまいます。
EC-CUBEの標準管理画面IP制限機能では、ロードバランサーを経由した接続において実際のクライアントIPではなく、ロードバランサーのIPアドレスが参照されるため、適切なIP制限ができない状態となります。
理由や原因
EC-CUBEの管理画面IP制限機能は、PHPの$_SERVER['REMOTE_ADDR']を参照してアクセス元IPを判定しています。ロードバランサー配下では、この値がロードバランサーのIPアドレスとなり、実際のクライアントIPはX-Forwarded-Forヘッダーに格納されます。
EC-CUBEの標準機能ではX-Forwarded-Forヘッダーを考慮したIP制限には対応していないため、ロードバランサー配下での適切なIP制限を行うには、Webサーバ側またはEC-CUBE側での追加設定が必要となります。
解決策
方法1: mod_remoteip を使用する方法(推奨)
Apacheのmod_remoteipモジュールを使用することで、EC-CUBEのカスタマイズなしに対応可能です。
手順
- mod_remoteipモジュールを有効化します
sudo a2enmod remoteip
- Apache設定ファイル(httpd.confまたはバーチャルホスト設定)に以下を追加します
# ロードバランサーのIPアドレスを信頼するプロキシとして設定
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 10.0.0.0/8 # ロードバランサーのIPレンジに合わせて調整
RemoteIPTrustedProxy 172.16.0.0/12
RemoteIPTrustedProxy 192.168.0.0/16
- Apacheを再起動します
sudo systemctl restart apache2
- EC-CUBEの管理画面IP制限設定で実際のクライアントIPを設定します
方法2: EC-CUBEカスタマイズによる対応
mod_remoteipが使用できない場合は、EC-CUBE側をカスタマイズして対応します。
手順
- カスタマイズディレクトリにIP取得処理を作成します
// app/Customize/Service/IpService.php
<?php
namespace Customize\Service;
class IpService
{
public function getRealIpAddress(): string
{
// X-Forwarded-Forヘッダーを優先的に取得
$headers = getallheaders();
if (isset($headers['X-Forwarded-For'])) {
$ips = explode(',', $headers['X-Forwarded-For']);
return trim($ips[0]); // 最初のIPを取得
}
return $_SERVER['REMOTE_ADDR'] ?? '';
}
}
- 管理画面IP制限処理をカスタマイズします
// app/Customize/EventListener/AdminIpListener.php
<?php
namespace Customize\EventListener;
use Customize\Service\IpService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class AdminIpListener implements EventSubscriberInterface
{
private $ipService;
public function __construct(IpService $ipService)
{
$this->ipService = $ipService;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 512]
];
}
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
// 管理画面へのアクセスかチェック
if (strpos($request->getPathInfo(), '/admin') === 0) {
$realIp = $this->ipService->getRealIpAddress();
// 元のREMOTE_ADDRを実際のIPに置き換え
$_SERVER['REMOTE_ADDR'] = $realIp;
}
}
}
- サービス設定を追加します
# app/Customize/Resource/config/services.yaml
services:
Customize\Service\IpService:
public: true
Customize\EventListener\AdminIpListener:
tags:
- { name: kernel.event_subscriber }
注意事項
X-Forwarded-Forヘッダーは改ざん可能なため、信頼できるプロキシ(ロードバランサー)からのアクセスのみを対象とすることが重要です。
ロードバランサーの設定でX-Forwarded-Forヘッダーが適切に設定されていることを事前に確認してください。
カスタマイズを行う場合は、バージョンアップ時の影響を考慮してテスト環境での検証を推奨します。