LoginSignup
2
2

More than 3 years have passed since last update.

接続元IPv4アドレスがAWS CloudFrontかを検証する方法

Last updated at Posted at 2020-06-16

はじめに

Amazon CloudFrontを使ってアクセスした際は接続元IPアドレスが「X-Forwarded-For」ヘッダに格納されます。
このヘッダには複数IPアドレスが列挙されることがあり、先頭からひとつずつ検証する必要があります。
このクラスは「CloudFront IPアドレスに一致するか」をAWS IPアドレスの範囲に基づいて検証しています。

HTTP接続用にGuzzleを使っていますので、必要に応じてインストールしてください。

検証用クラス

<?php
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;

class AmazonAddress
{
    const AMAZON_IP_RANGES_URL = "https://ip-ranges.amazonaws.com/ip-ranges.json";

    /**
     * 対象IPv4アドレスがAWS CloudFrontのIPv4かを判定する
     * 
     * @param string $remote_ip 対象IPv4アドレス
     * @return bool 判定結果(true=CloudFront)
     */
    public static function isCloudFrontIPv4Address($remote_ip)
    {
        $prefixes = static::getAwsIPv4Addresses('CLOUDFRONT');
        foreach ($prefixes as $prefix) {
            list($accept_ip, $mask) = explode('/', $prefix);
            $accept_long = ip2long($accept_ip) >> (32 - $mask);
            $remote_long = ip2long($remote_ip) >> (32 - $mask);
            if ($accept_long == $remote_long) {
                return true;
            }
        }
        return false;
    }

    /**
     * AWS IPv4レンジリストを返却する
     * リクエストコストを考慮する必要がある場合は、リクエスト結果キャッシュなど対策すること
     * サービス名は以下を参照:
     *   https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-ip-ranges.html
     * 
     * @param string $service_name サービス名
     * @return array IPv4レンジリスト
     */
    public static function getAwsIPv4Addresses($service_name)
    {
        $ip_prefixes = [];
        $client = new Client();
        $response = $client->get(
            static::AMAZON_IP_RANGES_URL,
            [
                RequestOptions::ALLOW_REDIRECTS => false,
                RequestOptions::TIMEOUT => 10,
                RequestOptions::CONNECT_TIMEOUT => 1
            ]
        );
        // 200以外が返却された場合は空配列を返却する
        if ($response->getStatusCode() != 200) {
            return $ip_prefixes;
        }
        $response_body = (string)$response->getBody();
        $response_json = json_decode($response_body);
        // JSONパースに失敗した場合は空配列を返却する
        if (json_last_error() !== JSON_ERROR_NONE) {
            return $ip_prefixes;
        }
        foreach ($response_json->prefixes as $item) {
            // 対象サービスを限定
            if ($item->service != $service_name) {
                continue;
            }
            $ip_prefixes[] = $item->ip_prefix;
        }
        return $ip_prefixes;
    }
}

使い方

AmazonAddress::isCloudFrontIPv4Address('52.46.54.119') // → true
AmazonAddress::isCloudFrontIPv4Address('1.1.1.1') // → false
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2