green snake
Photo by Pixabay on Pexels.com

FastAPIのセキュリティベストプラクティス:認証・認可からCORSまで


📋 記事のポイント(サマリー)

  • 誰向け?
    FastAPIで実運用レベルのAPIを構築したいが、セキュリティ強化に不安がある中級〜上級エンジニアさん
  • 学べること
    1. OAuth2・JWTによるトークン認証の基本設計
    2. ロールベースの認可(権限管理)実装方法
    3. CORS(クロスオリジンリソース共有)設定で安全にフロント連携
    4. APIキー発行・レートリミット導入で不正アクセスを防止
    5. セキュリティ診断ツールとの連携による脆弱性チェック
  • 得られる効果
    • 安全な認証/認可機構でAPIの不正利用を防ぎ、運用リスクを大幅に低減
    • フロントエンドや他サービスとの連携も安全かつスムーズに実現

🎯 対象読者

  • 企業内API開発者Dさん(30代)
    既に社内に公開中のFastAPIサービスに、強固な認証・認可を追加したい方
  • スタートアップEさん(25歳)
    新規プロダクトのAPI設計で、セキュリティ要件をプロトタイプ段階から担保したい方
  • フリーランスFさん(40代)
    クライアントの要件に応じて、APIキーやレート制御を素早く実装したい方

♿ アクセシビリティレベル

  • 読みやすさ:漢字・ひらがな・カタカナのバランスを配慮し、専門用語は注釈で補足
  • 構造化:見出し/サブ見出しを多用し、スクリーンリーダーでも把握しやすい階層設計
  • コード例:コメント付きかつシンプルに表示し、カラーコントラストに配慮
  • 要約:各章末に「要点まとめ」を設け、後から参照しやすい構成

1. はじめに:APIセキュリティの重要性

近年、APIを狙った攻撃が増加しており、認証・認可の不備やCORS設定ミスは重大な情報漏えいリスクにつながります。
FastAPIは高速かつ型安全性に優れたフレームワークですが、セキュリティ周りは開発者自身でしっかり設計・実装する必要があります。
本記事では、認証(Authentication)から認可(Authorization)、CORS設定、APIキー発行、レートリミット、さらに自動的に脆弱性を検出する診断ツールまで、一連のベストプラクティスをステップ・バイ・ステップでご紹介します♡

要点まとめ

  • API攻撃のリスクを理解し、対策を組み合わせることが重要
  • FastAPIの機能+外部ライブラリで堅牢な仕組みを実装

2. OAuth2+JWTで堅牢なトークン認証を実装

2.1 基本設計と必要パッケージ

OAuth2のパスワードフローとJWT(JSON Web Token)を組み合わせるのが一般的です。
必要パッケージ:

pip install python-jose[cryptography] passlib[bcrypt]

2.2 ユーザー認証とトークン発行のサンプル

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# ユーザー認証用ダミーDB
fake_users_db = {
    "alice": {"username": "alice", "hashed_password": pwd_context.hash("secret")}
}

def authenticate_user(username: str, password: str):
    user = fake_users_db.get(username)
    if not user or not pwd_context.verify(password, user["hashed_password"]):
        return False
    return user

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(status_code=400, detail="認証に失敗しました")
    access_token = create_access_token({"sub": user["username"]})
    return {"access_token": access_token, "token_type": "bearer"}

要点まとめ

  • OAuth2PasswordBearer でトークン取得エンドポイントを定義
  • JWTに有効期限 (exp) を付与し、安全性を担保

3. ロールベース認可できめ細かい権限管理

3.1 PydanticモデルでRole定義

from pydantic import BaseModel

class TokenData(BaseModel):
    username: str | None = None
    roles: list[str] = []

3.2 依存関数で認可チェック

from fastapi import Security

def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED, detail="トークン認証に失敗しました"
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        roles: list[str] = payload.get("roles", [])
    except JWTError:
        raise credentials_exception
    return TokenData(username=username, roles=roles)

def require_role(role: str):
    def role_checker(current: TokenData = Depends(get_current_user)):
        if role not in current.roles:
            raise HTTPException(status_code=403, detail="権限がありません")
    return Depends(role_checker)

@app.get("/admin")
async def read_admin_data(_ = require_role("admin")):
    return {"message": "管理者専用データです"}

要点まとめ

  • JWTペイロードに roles を含め、依存関数で権限をチェック
  • require_role("role_name") のように再利用性を高める

4. CORS設定でフロント連携を安全に

FastAPIでは CORSMiddleware を使って簡単に設定できます。

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://your-frontend.com"],  # 信頼するオリジン
    allow_credentials=True,
    allow_methods=["GET","POST","PUT","DELETE"],
    allow_headers=["*"],
)
  • allow_origins は必ず運用ドメインのみに限定しましょう。
  • ワイルドカード "*" は開発時のみ利用し、本番では避けるのがベストプラクティスです。

要点まとめ

  • 信頼できるオリジンだけを許可
  • 開発・本番で設定を分け、安全性を担保

5. APIキー発行とレートリミットで不正アクセス防止

5.1 APIキー管理

  1. ランダムな文字列をキーとして発行
  2. テーブルに key, owner, scopes などを保存
  3. ミドルウェアでリクエストヘッダ X-API-Key を検証
from fastapi import Header

async def verify_api_key(x_api_key: str = Header(...)):
    if x_api_key != "YOUR_STORED_API_KEY":
        raise HTTPException(status_code=403, detail="APIキーが無効です")

5.2 レートリミット導入例(slowapi

pip install slowapi
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.get("/limited")
@limiter.limit("5/minute")
async def limited_endpoint():
    return {"message": "これはレート制限付きエンドポイントです"}

要点まとめ

  • APIキーでクライアントを特定し、アクセス制御
  • レートリミットでブルートフォースやスクレイピングを抑制

6. セキュリティ診断ツールとの連携

  • Bandit:静的解析でPythonコードの脆弱性を検出
    pip install bandit
    bandit -r .
    
  • OWASP ZAP:動的解析で実際のAPIをスキャン
    • CI/CDパイプラインに組み込むと、自動でセキュリティテストが実行可能

要点まとめ

  • 静的/動的解析を組み合わせ、早期に脆弱性を発見
  • CI/CDへの自動統合で品質保証を強化

7. まとめと次のステップ

本記事では、FastAPIで実践的なセキュリティ対策を一通りご紹介しました。

  1. OAuth2+JWTのトークン認証設計
  2. ロールベース認可による権限管理
  3. CORS設定で安全なフロント連携
  4. APIキー発行・レートリミットで不正アクセス防止
  5. BanditやOWASP ZAPでの自動脆弱性診断

これらを組み合わせることで、安全かつ信頼性の高いAPIが構築できます。次のステップとしては、さらなるセキュリティ強化(監査ログの収集、WAF連携など)にも挑戦してみてくださいね♡

投稿者 greeden

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)