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

クロスサイトリクエストフォージェリ(CSRF)

説明

クロスサイトリクエストフォージェリ(CSRF)は、悪意あるWebサイトがユーザーのブラウザーを使って、別のサイトに意図しないリクエストを送らせる攻撃です。Cookieなど、ブラウザーが自動送信する認証情報を悪用し、データの変更や削除など、攻撃者が意図する操作を実行させます。

想定される影響

  • データの改ざん: ユーザーの意思に反してデータが変更される可能性があります。
  • ユーザー権限の悪用: 被害者に許可されたアカウント設定の変更や管理操作が実行される可能性があります。
  • サービスの悪用: アプリケーションの機能が悪用され、被害につながる可能性があります。

対処方法

  • 状態を変更するリクエストにはCSRFトークンを使用してください。
  • サーバーでOriginなどを検証し、信頼できない送信元のリクエストを拒否してください。
  • GETリクエストで状態を変更しないでください。CSRF対策とともに、HTTPSと適切なSameSite Cookie設定を使用してください。

例

Django

最初の例は、CsrfViewMiddlewareや他のCSRF保護がない構成を想定しています。デコレーターがないという理由だけでは、保護がないとは判断できません。

変更前

python
# CSRF保護のないDjangoの例
from django.http import HttpResponse

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

変更後

python
# DjangoのCSRF保護の例
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検証なしでPOSTリクエストを処理します。
  • 変更後: @csrf_protectでCSRFトークンを検証します。

Flask

Flaskの例は、your_secret_key環境変数に十分に強いシークレットキーが設定されていることを前提とします。保護対象のフォームやAJAXリクエストには、CSRFトークンを含めてください。

変更前

python
# CSRF保護のないFlaskの例
from flask import Flask, request

app = Flask(__name__)

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

変更後

python
# FlaskのCSRF保護の例
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():
    # CSRFトークンを検証してリクエストを処理
    return "Request processed"

説明:

  • 変更前: CSRF検証なしでPOSTリクエストを処理します。
  • 変更後: flask_wtf.csrf.CSRFProtectでCSRFトークンを検証します。

FastAPI

Cookie認証を使用し、状態を変更するエンドポイントを想定しています。2つ目の例はOriginを検証し、ヘッダーがない場合や許可リストと一致しない場合に拒否します。認証と認可は別途実装する必要があります。

変更前

python
# CSRF保護のない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検証なしでPOSTリクエストを処理します。
  • 変更後: Originの検証で、許可していない送信元のリクエストを拒否します。TrustedHostMiddlewareは宛先のHostヘッダーを検査するもので、それ自体はCSRFを防ぎません。

参考資料