Content-Type の厳格チェック¶
🌐 AI と人間による翻訳
この翻訳は、人間のガイドに基づいて AI によって作成されました。🤝
原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖
AI LLM をより適切に誘導するのを手伝う ことで、この翻訳を改善できます。
既定では、FastAPI は JSON リクエストボディに対して厳格な Content-Type ヘッダーのチェックを行います。つまり、JSON のリクエストを JSON として解析するには、有効な Content-Type ヘッダー(例: application/json)を必ず含める必要があります。
CSRF のリスク¶
この既定の挙動は、ある特定の状況における Cross-Site Request Forgery(CSRF)攻撃の一種に対する保護を提供します。
これらの攻撃は、次の条件を満たすときにブラウザが CORS のプリフライトチェックを行わずにスクリプトからリクエストを送信できる事実を悪用します。
Content-Typeヘッダーがない(例:Blobをボディにしてfetch()を使う)- かつ、いかなる認証情報も送信しない
この種の攻撃は主に次のような場合に関係します。
- アプリケーションがローカル(例:
localhost)または社内ネットワークで動作している - かつ、アプリに認証がなく、同一ネットワークからのリクエストは信頼できると想定している
攻撃例¶
ローカルで AI エージェントを実行できる仕組みを構築したとします。
それは次の API を提供します。
http://localhost:8000/v1/agents/multivac
フロントエンドもあります。
http://localhost:8000
豆知識
両方とも同じホストであることに注意してください。
そのフロントエンドを使って、AI エージェントに自分の代わりに作業をさせられます。
それが「公開インターネット」ではなくローカルで動作しているため、ローカルネットワークへのアクセスを信頼し、認証を一切設定しないことにしたとします。
すると、ユーザーの一人がそれをインストールしてローカルで実行できます。
その後、例えば次のような悪意のあるサイトを開く可能性があります。
https://evilhackers.example.com
そしてその悪意のあるサイトが、Blob をボディにした fetch() を使ってローカルの API にリクエストを送信します。
http://localhost:8000/v1/agents/multivac
悪意のあるサイトとローカルアプリのホストは異なるにもかかわらず、ブラウザは次の理由で CORS のプリフライトリクエストを発行しません。
- 認証なしで動作しており、認証情報を送る必要がないため
- ブラウザは(
Content-Typeヘッダーがないため)JSON を送っていないと判断するため
その結果、悪意のあるサイトがローカルの AI エージェントに、ユーザーの元上司に怒りのメッセージを送らせることができてしまいます... あるいは、もっと悪いことも。 😅
公開インターネット¶
アプリが公開インターネット上にある場合、「ネットワークを信頼」して認証なしで誰にでも特権的なリクエストを送らせることはしないはずです。
攻撃者は単にスクリプトを実行して API にリクエストを送れます。ブラウザを介する必要がないため、すでに特権エンドポイントは保護しているでしょう。
その場合、これはあなたには当てはまらない攻撃/リスクです。
このリスクと攻撃が主に問題になるのは、アプリがローカルネットワークで動作し、それだけが前提の保護となっている場合です。
Content-Type なしのリクエストを許可する¶
Content-Type ヘッダーを送らないクライアントをサポートする必要がある場合は、strict_content_type=False を設定して厳格チェックを無効化できます。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(strict_content_type=False)
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
return item
この設定では、Content-Type ヘッダーがないリクエストでもボディが JSON として解析されます。これは古いバージョンの FastAPI と同じ挙動です。
情報
この挙動と設定は FastAPI 0.132.0 で追加されました。