FastAPIのセキュリティベストプラクティス:認証・認可からCORSまで
📋 記事のポイント(サマリー)
- 誰向け?
 FastAPIで実運用レベルのAPIを構築したいが、セキュリティ強化に不安がある中級〜上級エンジニアさん
- 学べること
- OAuth2・JWTによるトークン認証の基本設計
- ロールベースの認可(権限管理)実装方法
- CORS(クロスオリジンリソース共有)設定で安全にフロント連携
- APIキー発行・レートリミット導入で不正アクセスを防止
- セキュリティ診断ツールとの連携による脆弱性チェック
 
- 得られる効果
- 安全な認証/認可機構で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キー管理
- ランダムな文字列をキーとして発行
- テーブルに key,owner,scopesなどを保存
- ミドルウェアでリクエストヘッダ 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で実践的なセキュリティ対策を一通りご紹介しました。
- OAuth2+JWTのトークン認証設計
- ロールベース認可による権限管理
- CORS設定で安全なフロント連携
- APIキー発行・レートリミットで不正アクセス防止
- BanditやOWASP ZAPでの自動脆弱性診断
これらを組み合わせることで、安全かつ信頼性の高いAPIが構築できます。次のステップとしては、さらなるセキュリティ強化(監査ログの収集、WAF連携など)にも挑戦してみてくださいね♡
