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連携など)にも挑戦してみてくださいね♡