Lambda + API Gateway の構成で、特定のホスト(ヘッダーの値)以外のリクエストを 500 Internal Server Error で返す処理を検討します。
方法
Lambda 関数内で Host ヘッダーをチェック
API Gateway のリクエスト情報 (event) から headers["X-Forwarded-For"] を取得し、許可されたホストかどうかを判定します。
許可されていないホストなら 500 エラーを返す
許可リストにない場合、500 の HTTP ステータスコードを返します。
X-Forwarded-For ヘッダーとは?
X-Forwarded-For は、プロキシやロードバランサを経由したリクエストの元のクライアント IP アドレスを取得するための HTTP ヘッダーです。
通常、クライアントが直接サーバーにリクエストすると、サーバーは REMOTE_ADDR などで直接クライアントの IP アドレスを取得できます。しかし、リクエストが プロキシ や ロードバランサ を経由すると、サーバー側からはプロキシの IP アドレスしか見えません。
そこで、プロキシやロードバランサは X-Forwarded-For ヘッダーを追加し、元のクライアント IP を記録します。
例
- 一番左のIPが「元のクライアントのIP」
- 右側に行くほど、経由したプロキシやロードバランサの IP が追加される
X-Forwarded-For: 203.0.113.5, 192.168.1.1, 10.0.0.1
- 203.0.113.5 → 元のクライアント
- 192.168.1.1 → 中継プロキシ
- 10.0.0.1 → 最後のプロキシ(API Gateway など)
実装例(X-Forwarded-Forで制限)
ALLOWED_IPS = {"203.0.113.5"}
def lambda_handler(event, context):
headers = event.get("headers", {})
x_forwarded_for = headers.get("X-Forwarded-For", "")
client_ip = x_forwarded_for.split(",")[0] if x_forwarded_for else "Unknown"
if client_ip not in ALLOWED_IPS:
return {
"statusCode": 403,
"body": "Forbidden"
}
return {
"statusCode": 200,
"body": f"Access granted for {client_ip}"
}
注意点
偽装の可能性がある
- X-Forwarded-For はクライアントが自由に書き換えられるため、悪意のあるユーザーが偽の IP を設定することができます。
- AWS の ALB や CloudFront などの信頼できるプロキシを通す場合は、信頼できるリスト (trusted proxies) を考慮して処理するとよいです。
referer ヘッダーとは?
Referer(リファラー)ヘッダーは、現在のリクエストがどこから来たのか を示す HTTP ヘッダーの一つです。
例えば、あるウェブページ(https://example.com)のリンクをクリックして別のページ(https://target.com)に移動した場合、https://target.com へのリクエストには以下のような Referer ヘッダーが含まれます。
Referer: https://example.com
Referer ヘッダーの用途
- セキュリティ対策
- 許可されたページ(ドメイン)のみアクセスを許可する
- CSRF(クロスサイトリクエストフォージェリ)対策
- アナリティクス
- どのサイトからの流入が多いか分析
- マーケティング効果測定
- 画像やリソースのホットリンク防止
- 他のサイトからの無断直リンクを防ぐ
Referer ヘッダーの注意点
- ブラウザや設定によって送信されない場合がある
- セキュリティ設定によって Referer が削除されることがある
- HTTPS → HTTP の遷移では送信されない(no-referrer-when-downgrade)
- スペルミスに注意("Referer" ではなく "Referrer")
- Referer は「Referrer(リファラー)」のスペルミスが標準になっている
- Referrer-Policy による影響
- Referrer-Policy HTTP ヘッダーの設定により Referer の送信内容が制御される
- 例: no-referrer にすると Referer は送信されない
実装例(refererで制限)
Referer ヘッダーを使って、特定のサイトからのリクエストのみ許可するように制限できます。
方法
- 環境変数 (ENV) で本番環境かどうかを判定
- 許可する Referer リスト (ALLOWED_REFERRERS) を設定
- Referer ヘッダーの値をチェック
- 許可リストにない場合は 403 Forbidden を返す
- 開発環境 (ENV=development) では制限なし
実装例
import json import os # 許可する Referer のリスト(ドメインのみ指定) ALLOWED_REFERRERS = { "https://example.com", "https://sub.example.com" } # 環境変数で環境を判定(デフォルトは 'development') ENV = os.getenv("ENV", "development") def lambda_handler(event, context): headers = event.get("headers", {}) referer = headers.get("Referer", "") # 本番環境のみ Referer 制限を適用 if ENV == "production" and not any(referer.startswith(r) for r in ALLOWED_REFERRERS): return { "statusCode": 403, "body": json.dumps({"message": "Forbidden: Invalid Referer"}), } return { "statusCode": 200, "body": json.dumps({"message": f"Access granted for Referer: {referer}"}), }
ポイント
- Referer ヘッダーは省略されることがある
- ブラウザの設定やセキュリティ機能で Referer が送信されないことがあるため、Referer が空でも許可するか検討する。
- startswith() を使って Referer をチェック
- https://example.com/page1 のようなパス付きのURLも考慮
- CORS 設定と併用可能
- Referer 制限と CORS の Access-Control-Allow-Origin 設定を組み合わせると、より強力なセキュリティ対策になる