🦀
トークンでの認証とCookieでの認証が混ざると危険な理由とは?
はじめに
Webアプリをリニューアルするタイミングで、従来はCookieベースの認証だけで運用していたものを、フロントエンドとバックエンドを分離し、トークンベースの認証に置き換えることがあります。
このような場合、認証方式が混ざることで思わぬセキュリティリスクが生じることがあります。本記事では、具体的にどのような問題が起こるのかを整理していきたいと思います。
今回は以下のようなケースで考えてみました。
実装パターン:
- サーバー側で
setcookie(httponlyではない)でJWTトークンを設定 - フロントエンドでトークンを
cookieで管理 - リクエスト時に
Authorization: Bearer <token>ヘッダーで送信 - サーバー側でJWTをデコードして認証
この「トークンとCookieを混ぜる」実装パターンですが危険な落とし穴があります。
なぜ危険なのか、詳しく見ていきましょう。
2つの注意点
1. XSSへの脆弱性
JWTをJavaScriptで読める状態(HttpOnlyでないcookieやlocalStorage)に保存している場合、ページ内に悪意あるスクリプトが混入すると、以下のようにトークンを簡単に盗まれる危険があります。
// 1. Cookieから取得
const cookieToken = document.cookie
.split('; ')
.find(row => row.startsWith('jwt='))
?.split('=')[1];
// 2. localStorageからも取得
const localToken = localStorage.getItem('jwt');
// 攻撃者が両方のトークンを取得可能
2. CSRF(クロスサイトリクエストフォージェリ)の攻撃性が高い理由
CookieにJWTを保存している場合、ブラウザは自動でそのcookieをリクエストに付与します。この特性が原因で、攻撃者が別サイトからユーザーになりすましリクエストを送信できる可能性があります。
※ クロスオリジンリクエストでも、適切に設定されていればCookieは自動で送信されます
上記のように、XSSやCSRFにはそれぞれ異なる危険性があります。そのため、認証方式を混ぜることは基本的に避けるべきです。
- Cookieで管理する場合は、
HttpOnlyを付け、SameSite属性を設定することでXSSやCSRFリスクを低減できます。 - トークンベースの認証の場合は、localStorageや永続Cookieよりも、短命のアクセストークンをメモリで管理する方が安全です。
こうした設計方針を理解しておくことで、実装時のリスクを減らしつつ、必要に応じて柔軟に対応できるようになります。
Discussion