Originの検証不備

ブラウザーが認証情報を自動送信するリクエストには、適切な送信元検証とCSRF対策を適用してください。

説明

ブラウザーがCookieなどの認証情報を自動送信するリクエストで、送信元検証やCSRF対策が不足すると、攻撃者が別のサイトからユーザーの権限で意図しないリクエストを送る可能性があります。Originの検証はユーザー認証の代わりにはなりません。ブラウザー以外のクライアントは、このヘッダーを自分で指定できます。

想定される影響

  • CSRF: 攻撃者がユーザーに代わって悪意のあるリクエストを送り、不正アクセスを試みる可能性があります。
  • 情報漏えい: リクエストによって情報の公開や転送の設定が変わると、機密情報が漏えいするおそれがあります。
  • データの改ざん: 攻撃者がデータを変更し、システムの完全性を損なう可能性があります。

対処方法

  • サーバー側で送信元のスキーム、ホスト、ポートを正確な許可リストと比較してください。Originヘッダーがない場合と、送信元がnullの場合の扱いも決めてください。
  • ブラウザーのCookie認証を使う状態変更リクエストには、フレームワークのCSRFトークン検証を適用してください。
  • CORSでは、信頼する送信元だけにレスポンスの読み取りを許可してください。CORSだけでCSRF対策や認証・権限確認を置き換えないでください。

例

Cookie認証を使うリクエスト処理の抜粋です。認証と権限確認は別途適用してください。Flaskのyour_secret_key環境変数には、十分な乱数性を持つシークレットを事前に供給し、クライアントから有効なCSRFトークンを送る必要があります。

Django

変更前

python
# Djangoの変更前の例
from django.http import HttpResponse

def my_view(request):
    if request.method == 'POST':
        # CSRF検証なしでリクエストを処理
        return HttpResponse("Request processed")

変更後

python
# Djangoの変更後の例
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_view(request):
    if request.method == 'POST':
        # CSRFトークンを検証してリクエストを処理
        return HttpResponse("Request processed")

説明:

  • 変更前: この抜粋にはCSRF対策が示されていません。他の層でも保護されていないCookie認証のリクエストは、CSRF攻撃にさらされる可能性があります。
  • 変更後: @csrf_protectでCSRF検証を適用します。変更前でもCsrfViewMiddlewareが有効なら保護される場合があるため、デコレーターがないことだけでは判断できません。

Flask

変更前

python
# Flaskの変更前の例
from flask import Flask, request

app = Flask(__name__)

@app.route('/submit', methods=['POST'])
def submit():
    # CSRF検証なしでリクエストを処理
    return "Request processed"

変更後

python
# Flaskの変更後の例
import os
from flask import Flask, request
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv("your_secret_key").encode()
csrf = CSRFProtect(app)

@app.route('/submit', methods=['POST'])
def submit():
    return "Request processed"

説明:

  • 変更前: この抜粋にはCSRF対策が示されていません。他の層でも保護されていないCookie認証のリクエストは、CSRF攻撃にさらされる可能性があります。
  • 変更後: flask_wtf.csrf.CSRFProtectでCSRFトークンを検証します。

FastAPI

変更前

python
# FastAPIの変更前の例
from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/submit")
async def submit(request: Request):
    # CSRF検証なしでリクエストを処理
    return {"message": "Request processed"}

変更後

python
# FastAPIの変更後の例
from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.trustedhost import TrustedHostMiddleware

app = FastAPI()

# 信頼するホストを設定
app.add_middleware(
    TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]
)

@app.post("/submit")
async def submit(request: Request):
    origin = request.headers.get('origin')
    if origin not in ["https://example.com", "https://www.example.com"]:
        raise HTTPException(status_code=403, detail="Invalid origin")
    # リクエストを処理
    return {"message": "Request processed"}

説明:

  • 変更前: この抜粋にはCSRF対策が示されていません。他の層でも保護されていないCookie認証のリクエストは、CSRF攻撃にさらされる可能性があります。
  • 変更後: Originがない場合や許可リストにない値を拒否します。TrustedHostMiddlewareは宛先のHostを確認する別の機能であり、CSRF対策を置き換えるものではありません。

参考資料