preflightで確認する内容

一部のクロスオリジン要求の前に、ブラウザーはOPTIONSを送り、送信元、メソッド、要求ヘッダーが許可されるかを確認します。手順はFetch標準のCORSプロトコルで定義されています。すべてのクロスオリジン要求にpreflightが付くわけではありません。メソッドやヘッダーがCORS safelistの条件外の場合や、application/jsonのように許可リスト対象でないContent-Typeを使う場合に必要となり得ます。ブラウザーはAccess-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headersなどを調べて実要求を送るか判断します。

キャッシュは権限ではない

Access-Control-Max-Ageは成功したpreflight結果を再利用する期間の目安をサーバーが示しますが、ブラウザーごとの上限やキャッシュ動作があるため指定期間が保証されるわけではありません。preflight用キャッシュは通常のHTTP応答キャッシュとも別です。実要求には別途、認証・認可・入力検証が必要です。OPTIONSへの許可応答は、後続要求の成功やデータ閲覧権限を意味しません。

資格情報とOriginの照合

CookieやHTTP認証情報をクロスオリジン要求に含めるには、クライアントのcredentials設定とサーバーのAccess-Control-Allow-Credentials: trueが整合する必要があります。資格情報付き応答ではAccess-Control-Allow-Origin: *を使えません。受け取ったOriginを無条件に反射するのは安全な許可リストではありません。信頼するOriginを明示的に照合し、動的な応答ではVary: Originも検討します。CORSヘッダーはブラウザーのスクリプトに応答を公開するかを制御し、サーバー側のアクセス制御を置き換えません。

OWASPのセキュリティ専門家によるCSRFの見解

OWASPのセキュリティ専門家向け指針は、CORSを包括的なCSRF防御として扱わないよう説明しています。フォームに近いsafelisted要求はpreflightなしでサーバーに届くことがあります。またCORSが応答閲覧を止めても、要求が処理されなかったとは限りません。状態変更操作には脅威モデルに合ったサーバー側対策を用い、CSRFトークン、適切なSameSite Cookie、OriginまたはReferer検証などを組み合わせます。Cookieが自動送信されるサービスは、CORSの許可範囲だけでCSRFリスクがなくなったと判断してはいけません。

実装レビューの要点

開発者ツールでOPTIONSと実要求を分けて確認し、許可するOrigin・メソッド・ヘッダーと資格情報の組み合わせを試験します。ワイルドカードやOriginの反射、preflight失敗時に状態変更が起きないかも確認してください。ここでのセキュリティ上の見解はOWASPのCSRF分析に基づき、Fetch標準はプロトコル動作を定義します。両者の役割は異なります。

参考資料