サーバーサイドリクエストフォージェリ

サーバーサイドリクエストフォージェリ(SSRF)

説明

サーバーサイドリクエストフォージェリ(SSRF)は、攻撃者がユーザー入力を悪用し、サーバーに本来の用途にない宛先への要求を送らせる問題です。攻撃者が直接接続できない内部ネットワークや機密データへアクセスする経路になる可能性があります。

想定される影響

  • 内部ネットワークへのアクセス: サーバーを経由して内部サービスに到達されるおそれがあります。
  • 情報漏えい: 内部システムが返したデータを取得される可能性があります。
  • サービス停止: 悪意のある要求によってサービスが停止するおそれがあります。

対処方法

  • 外部へ要求を送る前に入力を検証してください。
  • ユーザーからURLを受け取るより、識別子から固定URLを選ぶサーバー管理の対応表を優先してください。
  • URLの入力が必要な場合は、標準のパーサーでスキームとホスト名を分離し、サーバーが管理する許可リストと正確に比較してください。
  • 自動リダイレクトを無効にするか、毎回宛先を再検証してください。想定外のプライベートIP・リンクローカルアドレスへの名前解決や、意図しないプロキシの使用を防いでください。

例

変更前

python
# ユーザーが指定する送信先
from flask import Flask, request
import requests

app = Flask(__name__)

@app.route('/fetch')
def fetch():
    url = request.args.get('url')
    response = requests.get(url)
    return response.content

変更後

python
# 固定の宛先と応答制限
from flask import Flask, request, abort, Response
import requests

app = Flask(__name__)

@app.route('/fetch')
def fetch():
    target_id = request.args.get('target')
    # ユーザーは識別子だけを選び、実際のURLは固定の分岐で設定する
    if target_id == "status":
        url = "https://status.example.com/health"
    elif target_id == "catalog":
        url = "https://api.example.com/v1/catalog"
    else:
        abort(400)

    max_response_bytes = 1024 * 1024
    chunks = []
    total = 0
    with requests.get(
        url, timeout=3, allow_redirects=False, stream=True
    ) as response:
        for chunk in response.iter_content(chunk_size=64 * 1024):
            total += len(chunk)
            if total > max_response_bytes:
                abort(502)
            chunks.append(chunk)
        status_code = response.status_code

    proxied = Response(
        b''.join(chunks),
        status=status_code,
        content_type="application/octet-stream",
    )
    proxied.headers["X-Content-Type-Options"] = "nosniff"
    return proxied

説明:

  • 変更前: 未検証の入力が送信先を決めるため、SSRFに悪用されるおそれがあります。
  • 変更後: 許可した識別子からサーバー管理の固定URLを選び、それ以外を拒否します。リダイレクトを無効にし、接続・読み取りの待機時間と1 MiBの応答サイズ上限を設定し、コンテンツタイプとnosniffヘッダーを固定します。timeout=3は処理全体の3秒制限ではないため、必要な全体の期限やネットワーク送信ポリシーは別途構成してください。

参考資料