こんにちは。技術チームの武山です。
先日行われた陳さんによる「認証基盤」勉強会の内容を共有したいと思います。
1.このような勉強会を開こうと思ったきっかけ
- 最近、当社のシステムと大手ECサイトとの間でAPI連携を行いました。その際にAPI認証のベストプラクティスを知ることができました。
- また他社のサービスでの認証方式も興味深い事例があります。
- 最近社内でリリースしたPWAでも認証が問題になりました。
以上のような経緯で、認証基盤の問題について課内で共有しておいた方がいいのではないかと考えました。
2.用語の整理
Webサービスの認証関係の言葉には厳密には三種類あります。
「識別」、「認証」、「認可」という三つの言葉はどう違うのでしょうか?
この三つの用語は以下のように整理できると思います。
- 「識別」(Identification) – 個人(ユーザー)にシステム内でユニークなidを付与すること。
- 「認証」(Authentication) – 個人がユーザーその人であることを確認すること・またその方法論。
- 「認可」(Authorization) – 個人に対してシステム内で何をして良いか決めること・またその方法論
このような分類とは裏腹に、実務上は、「識別」と「認証」はOne Stepで行います。
Webサイトに提出するID と Pwdのペアがそれぞれ、「識別」と「認証」の役割を担います。
3.典型的な認証の方法
Webサービスの認証には大きく分けて2種類あります。
- Session-Cookie を使う方法
- JWT (Json Access Token) を使う方法
1.Session-Cookieを使う認証
Session-Cookieを使う認証では、初回アクセス時にサーバーがSession-Cookieと呼ばれるCookieを発行し、クライアントがアクセスのたびにそれをサーバーに送信します。
サーバーはDBなどにSession-Cookieの内容(Session-ID)を保存しておいて、送信されてきたCookieの内容と比べることで認証を行います。
2.JWTを使う認証
JWT (JSON Web Token)を使った認証では、初回アクセス時に、サーバーが生成したトークンをクライアントが受け取り、そのアクセスのたびにサーバーに送信する点は同じですが、サーバーはトークンそのものを保持せず、トークン検証のための秘密鍵「secret」(アルゴリズムに共通鍵を使う場合、共通鍵)。
だけを保持します。
サーバーは、IDなどユーザーに関する情報をクライアントから送られてきたJWTから取り出すことができます。また、JWTが改ざんされていない事を、サーバーに保持している秘密鍵 or 共通鍵を使い検証することができます。
トークンの管理をクライアントサイドで行うという点で、サーバーサイドの負担が少ないというメリットがあります。
JWTのデータの構成
JWT は、 {ヘッダ}.{ペイロード}.{署名} の3つのセクションからなる文字列です。
- ヘッダ : 暗号化アルゴリズムなどの情報を入れた部分
- ペイロード:ユーザに関する情報などを入れた部分
- 署名:ヘッダ+ペイロードを秘密鍵or共通鍵で暗号化した部分
注意:ヘッダ・ペイロードは平文(暗号化されていない文)のBASE64エンコーディングにすぎないので、ユーザーに見られてはいけないデータを入れてはいけない。
JWTを扱う際の注意事項
- 一度認可したJWTを無効化扱いすることはできない
- 有効期限を短くしたり、即時無効化する必要がある場合は別途仕組みを用意する必要あり
4.Session-Cookie vs JWT
Session-cookie |
Token |
|
保存先 |
Cookieはブラウザ Sessionはサーバーサイド |
クライアント |
改ざんを防ぐ |
✗ |
◯ |
クライアント |
Webブラウザ |
Webブラウザ Nativeアプリなど |
状態の保持 |
Statefull (リクエストのたびにサーバーでSession情報の参照と保存を行います。) |
Stateless (送られて来たTokenを検証するだけで済みます) |
クロスドメイン |
基本NG |
OK (bodyで渡す) |
Session-Cookieによる認証とJWTによる認証を比較しました。
5.現実の世界での認証
基本的なSession-Coookieによる認証と、JWTによる認証が理解できたので、現実世界の認証のプラクティスを見てみます。
- Amazon API
- FIDO 認証
Amazon APIの認証。
Amazon.comのAPIの認証では、Authorization Serverと Resource Server の 2種類のServerから、Access Token とRefresh Tokenを取得してそれを認証に使用します。
Access Token とRefresh Tokenの有効期間は、当然のことながら異なります。
Access Token の有効期間は1日程度であり、Refresh Tokenの有効期間はそれよりも長く設定されています。また、Access Tokenの再発行における認証と、Refresh Tokenの再発行手続きにおける認証はそれぞれ異なった方式で行います。これにより、万が一JWTが外部に流失した際の被害の拡大を防いでいます。
FIDO認証
FIDO認証は、比較的新しい認証方式です。
FIDO認証の最も大きな特徴は、パスワードレスである点です。
FIDO認証の技術的背景にあるのはsshに使用されている公開鍵認証方式です。あらかじめ、公開鍵と秘密鍵のペアを生成します。ログインの際はサーバーサイドからナンス(Number used once:一回限りの合言葉のようなデータ)をクライアント送ります。クライアントサイドで特殊なデバイスを使用し、生体認証に成功した場合に限って、秘密鍵で署名したナンスを送り返します。送り返されたナンスの検証に成功した場合に、認証に成功します。
このように、よりセキュアにするためにSession-CookieやJWTなど古典的な認証方式からさらに発展した認証方式が実際には使用されています。
6.感想
認証の話はややこしい話が多く、難しいですがWebサービスを作る上で必須でとても興味深いと思いました。