はじめに
以下では、主にWebアプリケーションにおけるセッション方式とアクセストークン方式(JWTなどが代表的)のログイン認証の概要と、セキュリティ対策について説明します。
1. セッション方式
1-1. セッション方式の概要
- ユーザー認証: ユーザーがIDとパスワードなどを送信し、サーバー側で正当性を確認します。
- セッションIDの発行: 認証成功後、サーバーはセッションIDを生成し、ブラウザに渡します。
- セッションIDの保存: 通常はCookieにセッションIDを含めて返却し、ブラウザ側で保持します。
- リクエストごとの確認: ユーザーが次のリクエストを送る際にはCookie内のセッションIDをサーバーに送信します。サーバーはそのセッションIDを自前のセッションストア(メモリ、DB、Redisなど)で照合し、ログイン済みかどうかを判定します。
1-2. セッション方式のメリット
- サーバー側でセッション管理を行うため、サーバーがセッションIDとユーザー情報を紐づけて保持します。
- ユーザー情報をサーバーが直接持つため、トークン単体でユーザー情報が漏えいするリスクは低いです。
- セッションストアを無効化や更新すれば、ユーザーを強制ログアウトできるなどセッション無効化が容易。
1-3. セッション方式のデメリット
- すべてのリクエストでサーバーサイドに問い合わせる必要がある(ただし、これは認証が関わる機能では一般的)。
- ステートフルになるため、サーバーをスケールアウトする際はセッションを共有できる仕組み(Sticky session や Redisなどの分散セッションストア)が必要。
- Cookieが必要になるため、Cookieに対するセキュリティ対策を講じなければいけない(XSS/CSRF対策など)。
2. アクセストークン方式
2-1. アクセストークン方式の概要
近年はJSON Web Token (JWT)などを用いて認証・認可を行うケースが一般的です。以下、JWTを例に流れを簡単に説明します。
- ログイン認証: ユーザーがIDとパスワードなどを送信し、サーバー側で正当性を確認します。
- アクセストークンの発行: 認証成功後、サーバーはアクセストークン(JWT) を生成し、クライアントに返却します。場合によってはリフレッシュトークン(長期間有効、再認証用)も発行します。
- トークンの保持: クライアント(ブラウザやアプリ)はトークンをCookieや**ブラウザのストレージ(localStorage、sessionStorage)**などに保持します。
- リクエストごとの送信: APIを呼び出す際には、Authorizationヘッダ(“Bearer {token}”)にアクセストークンを載せてサーバーに送ります。
- サーバー側のトークン検証: サーバーは受け取ったトークンを検証し、改ざんや期限切れのチェックを行い、問題なければ処理を続行します。
2-2. アクセストークン方式のメリット
- ステートレスでスケーラブル。サーバー側で状態を持たなくても、トークンに必要な認証・認可情報が含まれていれば検証のみで済む。
- マイクロサービスなど、多数のサービス間で認証情報を共有しやすい。
- 一定の期限が切れれば再ログインが必要となるため、セキュリティ向上につながる。
2-3. アクセストークン方式のデメリット
- トークン自体にユーザー情報や権限情報が含まれる場合、万が一トークンが盗まれると悪用されるリスクが高い。
- トークンをどこに保存するかを慎重に考えなければならない (localStorage、sessionStorage、Cookieなど)。
- 有効期限が切れる前にトークンを無効化するには別途メカニズムが必要(ブラックリスト管理など)。
- トークンのサイズが大きいと、それだけ通信量が増える。
3. セキュリティ上の主な脅威と対策
3-1. XSS (Cross-Site Scripting)
脆弱な入力フィールドなどを通じて、悪意のあるJavaScriptが注入される攻撃。
- 対策:
- HTMLエスケープを適切に行い、ユーザーが入力した値をそのまま表示しない。
- ReactやVueなどのフレームワークを使う場合は、原則デフォルトでXSS対策が施されるが、v-htmlやdangerouslySetInnerHTMLなどには注意が必要。
- クッキーへのアクセスを制限する(HttpOnly属性をつけるとJavaScriptからは参照不可)。
3-2. CSRF (Cross-Site Request Forgery)
利用者の意図しないリクエストを第三者のサイトから送らせる攻撃。
- 対策:
- CSRFトークンをフォームやリクエストに含める(サーバー側のセッション方式ではよく用いられる)。
- SameSite 属性をCookieに付与し、クロスサイトからのCookie送信を制限する。
- アクセストークン方式であれば、基本的にクライアントがヘッダに手動でトークンを付ける形になるため、CSRFの影響を受けにくいが、Cookieに保存する場合は注意が必要。
3-3. トークンまたはセッションIDの盗難
- セッション方式の場合: セッションIDが盗まれると、セッションハイジャックが発生し、なりすましが可能になる。
- アクセストークン方式の場合: アクセストークンが盗まれると、期限内であれば何度でも不正アクセスが可能。
- 対策:
- HTTPS(TLS)の導入: 通信全体を暗号化して、中間者攻撃などでCookieやトークンが覗き見されるのを防ぐ。
- Cookieには、Secure属性(HTTPS接続時のみ送信)とHttpOnly属性(JavaScriptからアクセス不可)を付与。
- アクセストークンを保存する場合は、なるべくHttpOnly Cookieで保存し、JavaScriptで触らない設計にするのが理想。
- localStorageやsessionStorageに保存する場合は、XSS攻撃によって盗難されるリスクがあるため、XSS対策を十分に行う。
- アクセストークンの期限を短くし、リフレッシュトークンによる更新プロセスを用意しておく。
- 不正アクセスや異常な行動を検知したら、**トークン無効化(ブラックリスト化)**やパスワード再設定を促す。
3-4. ブルートフォース攻撃
パスワードを総当たりで試される。
- 対策:
- ログイン試行回数の制限や、しきい値を超えたらCAPTCHAを出す、一定時間アカウントをロックするなど。
- パスワードは暗号学的に安全なハッシュ(bcrypt, Argon2など)でサーバーに保存する。
3-5. データ改ざん
JWTの場合、改ざんされたトークンを送られる可能性がある。
- 対策:
- JWTの署名部分を必ず検証する(秘密鍵や公開鍵で署名検証)。
- アルゴリズムをnoneにしないなど、設定ミスを防ぐ。
4. 選定のポイント
4-1. セッション方式を選ぶケース
- 従来型のWebアプリケーション(サーバーサイドレンダリングが中心など)で、サーバーセッションの仕組みが既にある場合。
- サーバー側をステートフルに管理しても問題ない、もしくはセッションストアの分散・共有が容易な環境。
- Cookieベースの認証に慣れているチームや既存サービスへの組み込みがしやすい場合。
4-2. アクセストークン方式を選ぶケース
- SPA (Single Page Application) や、モバイルアプリなど、フロントエンド/バックエンドを分離して開発する場合。
- マイクロサービスアーキテクチャなど、複数サービス間で認証・認可情報を共有する必要がある場合。
- 外部サービスとのやりとりが多く、認可情報をトークンに含めて使いまわすケース(OAuth2, OpenID Connectなど)。
まとめ
- セッション方式はサーバー側がユーザー状態を管理し、Cookieを使用する従来型の方法。ステートフルだが、実装が簡単でCSRFトークンなどオーソドックスな対策が取りやすい。
- **アクセストークン方式(JWTなど)**はサーバーがステートレスになりやすく、分散システムやSPAと相性が良い。ただし、トークン管理とセキュリティ対策が重要。
- 共通のセキュリティ対策としてHTTPSは必須、CookieにはHttpOnlyやSecure、SameSite属性を付ける、XSS/CSRFへの対策などを行う。
- 運用・環境に合わせてどちらを採用するかを決めつつ、セキュリティ対策をしっかりと行うことが大切です。
以上が、セッション方式とアクセストークン方式の認証の概要と主要なセキュリティ対策のまとめです。どちらも長所短所があるため、システム要件に応じて適切に選択・設計してください。