スマホアプリ作成にあたって、認証・認可周りで理解が曖昧だったところを整理してみました。
これで認証・認可の全体像を抑えているわけではなく、個人的に気になったところを列挙しているのであしからず。
そもそも認証と認可の違いって?
認証 (Authentication)
- 通信の相手が誰(何)であるかを確認すること
- (例) 運転免許証を使った本人確認
- イメージは証明書
認証を行うための3つの要素
要素 | 概要 |
---|---|
WHAT YOU ARE (inherence factor) | 顔や声など、その人自身によって認証する |
WHAT YOU HAVE (possession factor) | 身分証など、その人だけが持っているものを提示することによって認証する |
WHAT YOU KNOW (knowledge factor) | パスワードや秘密の質問など、その人だけが知っていることを提示して認証する |
より確実な認証を行いたい場合
- 一般的に、上記3つの要素のうちいずれか1つを満たすことで、認証が完了することが多い
- より確実な認証を行いたい場合は、Multi-Factor Authentication (MFA) という考え方で、複数のファクターを確認する
認可 (Authorization)
- とある特定の条件に対して、リソースアクセスの権限を与えること
- (例) 鍵。鍵があれば家に入ることができる
- イメージは鍵
認証と認可を分離して考える
- 多くの場合、認証と認可は密結合している
- 認証に基づく認可 (例) 運転免許証。写真によりある人が誰であるかを証明し、その上で、その人に対して運転の認可を行う
- しかし、時に認証と認可が分離していることがある
- 認証せずに認可することがある (例) 切符
- 認証して認可しないことが分散システム上である (例) Aシステムでユーザーの認証して、認可を行うBシステムに通知
- OAuthなどの概念を理解するためには、認証と認可を区別する必要がある
認証の基本方針
スマホアプリにおける認証の概要の基本です。
1. クライアントからサーバに認証情報を渡して
2. サーバで認証情報を検証して、Access Token を発行し
3. クライアントは API Call で Access Token を利用
4. サーバは Access Token を検証して、API のレスポンスを返す
+--------+ +--------+
| | | |
| |----(1) Credential ------------>| |
| | | |
| |<---(2) Access Token -----------| |
| | | |
| Client | | Server |
| | | |
| |----(3) API Call with Token --->| |
| | | |
| |<---(4) API Response -----------| |
| | | |
+--------+ +--------+
何を認証情報とするか
username, password
よくあるパターン。
クライアントが username, password をサーバーに送り、サーバーが検証し有効であればクライアントに Access Token を返す。
外部の ID Provider の Access Token
OAuth等で外部の IdP (ID Provider) からユーザの Access Token を取得し、それを認証情報として利用する。
サーバは(外部 IdP の) Access Token を検証し、有効であれば、クライアントに(自分のサービスの) Access Token を返す。
何を Token とするか
- 認証情報が検証ができたら、今度はサーバがクライアントに Access Token を返す
Tokenの種類
- ランダムな文字列を DB に保存する
- JWT を利用する
JWTって?
- JWT = JSON Web Token
- JSONをトークン化する仕組みのこと
- Signed JWT には署名がついているので、共通鍵や公開鍵があれば、Token の検証ができる
- Token の中に user_id や expiration time などの情報を埋め込めるので、DB による Token の管理が不要
Signed JWT
- JWS使ってSignatureつけられたJWT
- HeaderとPayloadとSignatureという3つのセグメントから構成される
- Header: 署名アルゴリズムなどを含むJSONを、URL-safe Base64 Encodingした文字列
- Payload: 実際に送信したいJSONデータそのものを、URL-safe Base64 Encodingした文字列
- Signature: HeaderとPayloadを “.” で連結した文字列に対して、Headerに指定されたアルゴリズムで署名をして、その署名をURL-safe Base64 Encodingした文字列
OAuthって?
ユーザー単位での API のアクセスコントロールがしたいっていう時によく登場するのが OAuth です。従来のBasic認証ではここが難しい。
- あくまでも認可の仕組み。認証には関係無い
- あらかじめ信頼関係を構築したサービス間で、ユーザの同意のもとに、セキュアにユーザの権限を受け渡しする仕組み。第三者のアプリケーションにユーザーの ID & パスワードを渡さない
- 従来のクレデンシャルによってすべての情報を参照・変更するという考え方から、認可された限定的な範囲で情報を扱える
- イメージは合鍵
何が嬉しいの
- サービス間で認可情報を受け渡せると,あるサービスがユーザの認可のもとで別のサービスの管理する情報の取得/追加/更新/削除などを行えるようになる
- OAuthに対応したサービスでは,ユーザが外部サービスにパスワードを教えることなく,認可情報の委譲が可能なため、Basic認証と比べて柔軟かつセキュアな運用が可能
登場人物
- User: アクセス権限の付与を行うユーザー自身
- Service Provider: FacebookやTwitterなどのように、OAuthをサポートしたAPIを提供しているサービス
- Consumer: それらのAPIを利用するInstagramやFoursquare、Pinterestなど、Service Providerが提供するAPIを利用する側のサービス
基本の仕組み
- ConsumerはService ProviderからあらかじめOAuth利用許可を得る
- UserがConsumerに,Service Providerから認可が必要な情報へのアクセス権を取得するように指示する
- ConsumerはバックグラウンドでService Providerにアクセスし,未認可のRequest Tokenを取得する
- ConsumerはUserをService Providerにリダイレクトさせる。この際Consumerは未認可のRequest TokenをURL Parameterに付加する
- UserはService Provider上でConsumerへのアクセス権委譲を許可する。この際Service Providerは未認可のRequest Tokenを認可済とする
- Service ProviderはUserをConsumerにリダイレクトさせる。この際Service Providerは認可済のRequest TokenをURLに含める
- onsumerはバックグラウンドでService Providerと通信を行い,認可済のRequest Tokenを実際のアクセス権を示すAccess Tokenと交換する
- Consumerは6)で得られたTokenを利用して,特定の情報にアクセスする
参考:第1回 OAuthとは?―OAuthの概念とOAuthでできること
OpenID Connectって?
OAuthは認可の仕組みだったのですけど、認可だけでなく認証も一緒にやりたいという時に登場するのが OpenID Connect です。
- OAuth2.0 を拡張したプロトコル
- 認証も認可もやりたい場合、OpenID (認証) もOAuth2.0 (認可) も実装しなくてはならない
- そこで実装しやすい OAuth2.0 を拡張して認証機能を追加したのが OpenID Connect
- さらによく利用されるユーザーの属性情報取得APIの仕様も定義されている
- OpenID Connect = 認証 + 認可 + 属性情報
OpenID Connectの基本の仕組み
- Relying PartyはOpenID Providerに認可リクエストを送る
- ユーザーはOpenID Providerにサイン・インし、認可をされる
- OpenID ProviderはID Tokenとアクセストークンで応答する
- Relying Partyは必要に応じて、アクセストークンを用いて、UserInfoエンドポイントにリクエストをおくる
- UserInfoエンドポイントはユーザーに紐づくアイデンティティ情報を返却する
用語 | 説明 |
---|---|
Relying Party (RP) | ユーザーが利用したいサービス。OpenID ProviderにID Tokenとアイデンティティ情報を要求する。 |
OpenID Provider (OP) | ユーザーの認証を行う機能を有するサーバー。 |
ID Token | 認証と認可の情報を含むJWT形式のトークン。 |
Access Token | UserInfoエンドポイントにアクセスするためのトークン。 |
UserInfo | Access Tokenを提示するクライアントに対して、アイデンティティ情報を提供する。 |
参考: 第一回 認証基盤のこれからを支えるOpenID Connect
JWT
JWTはOAuth2やOpenID Connectで使われているので、ここで見ておきます。
- JWT (JSON Web Token) とは、署名できるURLセーフ (URLで使用できる文字しか含んでいない) なトークンをつくる仕組み
- JWTはJWSまたはJWEのことを表すが、本稿ではJWSのことを指すことにする
- JWS (JSON Web Signature) は「JSONに電子署名をして、URL-safeな文字列として表現したもの」
- JWSに含むJSONは暗号化ではなく電子署名であるため、JSON の中身は誰でも見られるが、内容の改竄ができない
- (JWTの実例)
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzQ3MDg0MjcsInN1YiI6MX0.dB7ZblibH5vmFrELcjY4hezAk3-CVt0uEmknAQ2u3ac
JWTの特徴
- 発行者だけが、鍵を使ってトークンが正しいことを検証出来る
- 暗号化ではないので、JSON の中身は誰でも見られる
- しかしながら、電子署名であるため、JSON の変更は出来ない
- これによって、DBにトークンを保存したりすることなく、セキュアにトークンを発行できる
JWTの使い所
認証によく使われます。
- クライアントは認証サーバに認証情報を渡し、トークンを請求する
- 認証サーバは認証情報が正しいことを確認して、秘密鍵を使って署名された JWT (user_id と expiration_date を含む) を発行する
- クライアントはこの JWT を使って通常の API リクエストを行なう
- サーバは、秘密鍵を使って JWT を検証し、user_id を JSON から取り出し、処理を行なう
JWTは改竄されていないことを確認できるため、改竄されていなければ認証サーバが署名したということなので、信用できる情報 (user_id) というわけです。
JWTのユースケース
- OAuth 2.0のアクセストークン
- OpenID ConnectのIDトークン
- サービスをまたいだ認証機構
- メール認証のトークン
JWTの構造
- JWTの文字列の中には、ピリオド.が2つ含まれている。そこを境目にして3つの文字列に分割できる
- 1つ目: ヘッダ。どんなアルゴリズムで署名されているのか等のメタ情報を含む
- 2つ目: ペイロード。JSON本体に相当する情報
- 3つ目: 署名情報
電子署名
電子署名についてもJWTで出てきたので軽く触れておきます。
電子署名のモチベーション
- 電子文書は印影や筆跡が残らないために誰が作成したか証明しにくい → 署名者本人により作成されたことを証明したい
- 電子文書は改ざんしても証拠が残りにくい → 署名時点から電子文書が改ざんされていないことを証明したい
電子署名の仕組み
- 送信者は、電子文書(平文)のハッシュ値をとり、秘密鍵Aをもちいて、このハッシュ値を暗号化する
- 送信者はこの平文と暗号文と公開鍵Bを含んだ電子証明書を受信者に送る
- 受信者はハッシュ関数を用いて平文のハッシュ値をとり、電子証明書から公開鍵Bをとりだして暗号文を復号する
- 3の両者の値が一致すれば、送信されてきた平文は送信者本人が作成し、改ざんされていないことが証明される
参考: その7「電子署名のしくみと機能 ~本人証明と非改ざん証明~」
公開鍵と暗号鍵
ここも軽く触れておきます。イメージを掴むようなので正確性には欠けている点がございます。
公開鍵と暗号鍵のモチベーション
- 金庫に貴重品を詰めて送ってもらいたいが、金庫を閉める鍵と開ける鍵が同じだと、金庫を送るのと同じ労力をかけて慎重に鍵を送らないといけない → 閉めることしかできない鍵と開けることしかできない鍵を作ることで、鍵の配布を気軽にできるようにしよう
公開鍵と暗号鍵の仕組み
公開鍵
- 閉めることしかできない鍵。この鍵で暗号化したものを平文化するためには、秘密鍵が必要
- 公開してみんなにばらまいても問題ない
- 公開鍵から秘密鍵を作ることは困難
秘密鍵
- 開けることしかできない鍵。公開鍵で暗号化したものを平文化することができる鍵
- 秘密の鍵で、他人に見られてはいけない
- 秘密鍵から公開鍵を作ることができる。よって、秘密鍵だけ大事に保管しておけば、無くしてしまった公開鍵をあとから生成しなおす