Slide 1

Slide 1 text

30分で OpenID Connect 完全に理解したと言える ようになる勉強会

Slide 2

Slide 2 text

OAuthとOAuth認証とOpenID Connect » OAuthは権限移譲のプロトコル » 「OAuth認証」はプロフィールAPIによる認証 » OpenID ConnectはIDトークンによる認証 2

Slide 3

Slide 3 text

いきなり言われてもわからん… 認証・認可 権限委譲 IDトークン 3

Slide 4

Slide 4 text

OAuthとOpenID Connectの関係 OAuth OpenID Connect 拡張仕様 基礎となるOAuthを理解していないと OpenID Connectを理解するのは難しい 4

Slide 5

Slide 5 text

お品書き » そもそもOAuthってなに? » OAuth認証ってなにが問題なの? » OpenID ConnectはOAuthとなにが違うの? » ネイティブアプリやSPAではどう使うべき? 5

Slide 6

Slide 6 text

今日しない話 » OAuthの歴史 » OAuth2.0の詳細 » IDトークンの具体的な検証方法 6

Slide 7

Slide 7 text

※注意点 わかりやすさを優先しているため、一部説明や前提を省 略しています。 あらかじめご了承ください。 7

Slide 8

Slide 8 text

0. 認証・認可 8

Slide 9

Slide 9 text

そもそも認証・認可って? 認可(AuthZ) ● リソースアクセス権限をサードパーティのアプリに移譲すること ● 誰かに許可を与えること 認証(AuthN) ● 通信の相手が誰であるかを確認すること ● 個人の身元の確認 9

Slide 10

Slide 10 text

1. OAuth 10

Slide 11

Slide 11 text

OAuthとは? » 権限委譲のプロトコル » 認可のプロトコル 11

Slide 12

Slide 12 text

OAuthのメリット 安全性 サードパーティアプリにはリソースオー ナーのID・パスワードを教える必要がない 権限委譲 ユーザのリソースへのアクセス権限を サードパーティのアプリに移譲することが できる 12

Slide 13

Slide 13 text

OAuthのメリット 安全性 サードパーティアプリにはリソースオー ナーのID・パスワードを教える必要がない 権限委譲 ユーザのリソースへのアクセス権限を サードパーティのアプリに移譲することが できる 正直なに言ってるかわからん… 13

Slide 14

Slide 14 text

OAuthの流れを追ってみる 14

Slide 15

Slide 15 text

リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) OAuthの登場人物 15

Slide 16

Slide 16 text

① アプリ上で「Google Photoから画像を ダウンロードする」をクリック ① リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 16

Slide 17

Slide 17 text

① ② ② Google OAuthに対してGoogle Photoの アクセス権を要求 リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 17

Slide 18

Slide 18 text

① ② ③ ③ 「Google Photoへのアクセス権をクライアント に委譲すること」についてユーザーの意思を 確認 リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 18

Slide 19

Slide 19 text

① ② ③ ④ ④ 権限委譲に同意する リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 19

Slide 20

Slide 20 text

① ② ③ ④ ⑤ ⑤ 権限が委譲された証としてアクセストークンを 発行して、クライアントに渡す リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 20

Slide 21

Slide 21 text

① ② ③ ④ ⑤ ⑥ ⑥ クライアントはアクセストークンをもってGoogle PhotoのAPIにアクセスし、ユーザーの画像を要求 リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 21

Slide 22

Slide 22 text

① ② ③ ④ ⑤ ⑥ ⑦ ⑦ Google Photoはアクセストークンの有効性と紐づく権限を確認 問題がなければユーザーの画像をクライアントに渡す リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) 22

Slide 23

Slide 23 text

① ② ③ ④ ⑤ ⑥ ⑦ リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) こんな大変なことをやる メリットってなに? 23

Slide 24

Slide 24 text

① ② ③ ④ ⑤ ⑥ ⑦ リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) Point 1 ユーザーのID・パスワードがクライアントに伝わっていない →ID・パスワード入力に起因する脆弱性を防げる 24

Slide 25

Slide 25 text

① ② ③ ④ ⑤ ⑥ ⑦ リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) Point 2 ユーザーが許可してはじめて権限が委譲される ● 勝手にユーザー情報へのアクセスが許可されることはない ● 必要最小限の権限のみ委譲 25

Slide 26

Slide 26 text

① ② ③ ④ ⑤ ⑥ ⑦ リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) Point 3 アクセストークンで管理している ● 誰のリソースのどのような権限に紐づいているのか ● クライアントのリソースへのアクセス許可 26

Slide 27

Slide 27 text

① ② ③ ④ ⑤ ⑥ ⑦ リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) リソースサーバー (Google Photo) Point 3 アクセストークンで管理している ● 誰のリソースのどのような権限に紐づいているのか ● クライアントのリソースへのアクセス許可 OAuthはアクセストークンを発行するためのルール 27

Slide 28

Slide 28 text

クライアント (自分の作ったアプリ) リソースサーバー (Google Photo) OAuthのまとめ が への限定的なアクセスを アクセストークンの発行方法 (あるユーザーへの必要最小限の範囲の) 可能にするための 28

Slide 29

Slide 29 text

2. OAuth認証 29

Slide 30

Slide 30 text

認証のためのプロトコルという勘違い OAuth » 権限委譲のためのプロトコル » アプリのユーザー認証の話は出てこない リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) ①権限の委譲依頼 ②許可の確認 ③委譲許可 ④アクセストークン発 行 30

Slide 31

Slide 31 text

リソースオーナー (ユーザー) ③委譲許可 認証のためのプロトコルという勘違い OAuth » 権限委譲のためのプロトコル » アプリのユーザー認証の話は出てこない クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) ①権限の委譲依頼 ②許可の確認 ④アクセストークン発 行 じゃあなんでOAuth認証なんて言葉があるの? 31

Slide 32

Slide 32 text

プロフィールAPI (リソースサーバー) OAuth + プロフィールAPI だいたいこいつのせい 32

Slide 33

Slide 33 text

プロフィールAPI (リソースサーバー) OAuth + プロフィールAPI プロフィールAPI » プロフィール情報を提供するAPI クライアント (自分の作ったアプリ) ①アクセストークン ②プロフィール情報を 提供 33

Slide 34

Slide 34 text

☆ ☆ アクセストークンに紐づくプロフィール情報を要求 →返されたプロフィール情報のデータで認証 リソースオーナー (ユーザー) クライアント (自分の作ったアプリ) 認可サーバー (Google OAuth) プロフィールAPI (リソースサーバー) OAuth認証の仕組み 34

Slide 35

Slide 35 text

OAuth認証の 脆弱性 35

Slide 36

Slide 36 text

Step 1 悪意あるアプリが他人のアクセストークンを取得 →見た目上は普通に動作 Aさん (ユーザー) 悪意のある アプリ 認可サーバー (Google OAuth) OAuth認証の脆弱性 リソースサーバー (Google Photo) 普通に動作 Aさんのアクセストークン 36

Slide 37

Slide 37 text

Step 2 盗んだアクセストークンに差し替え →別のユーザーとしてログインできてしまう! 悪意のあるユーザー クライアント 認可サーバー (Google OAuth) プロフィールAPI (リソースサーバー) OAuth認証の脆弱性 盗んだAさんのアクセス トークンに差し替え Aさんのプロフィール情報 37

Slide 38

Slide 38 text

Step 2 盗んだアクセストークンに差し替え →別のユーザーとしてログインできてしまう! 悪意のあるユーザー クライアント 認可サーバー (Google OAuth) プロフィールAPI (リソースサーバー) OAuth認証の脆弱性 盗んだAさんのアクセス トークンに差し替え Aさんのプロフィール情報 Aさんとしてログイン 38

Slide 39

Slide 39 text

補足:OAuth認証 39 FacebookのOAuth認証 » アクセストークン検証用エンドポイント ⋄ /debug_token ⋄ 検証用データを取得 » アクセストークンを検証 ⋄ すり替えられていないことを担保

Slide 40

Slide 40 text

プロフィールAPI OAuth認証のまとめ から取得したプロフィールの情報を 使用して認証&ログインする方法 悪意あるアプリによってアクセストークンを盗まれた場合、 別のユーザーになりすましができる脆弱性がある 40

Slide 41

Slide 41 text

3. OpenID Connect 41

Slide 42

Slide 42 text

OpenID Connectとは? OpenID Connect(OIDC) » クライアントが認証できるプロトコル » リソースアクセス(認可)も可能 » OAuthの拡張仕様 OpenID Connect (OIDC) = OAuth + IDトークン + UserInfoエンドポイント 42

Slide 43

Slide 43 text

OpenID Connectとは? OpenID Connect(OIDC) » クライアントが認証できるプロトコル » リソースアクセス(認可)も可能 » OAuthの拡張仕様 OpenID Connect (OIDC) = OAuth + IDトークン + UserInfoエンドポイント Point! 43

Slide 44

Slide 44 text

OpenID Connectとは? 三種類のフロー » 認可フロー ⋄ 安全にclient secretを保存できるクライアント用(サーバー) » インプリシットフロー ⋄ 安全にclient secretを保存できないクライアント用(アプリ) » ハイブリットフロー ⋄ 安全にアクセストークンや IDトークンを保存できない クライアント用(SPA) 44

Slide 45

Slide 45 text

OpenID Connectとは? 三種類のフロー » 認可フロー ⋄ 安全にclient secretを保存できるクライアント用(サーバー) » インプリシットフロー ⋄ 安全にclient secretを保存できないクライアント用(アプリ) » ハイブリットフロー ⋄ 安全にアクセストークンや IDトークンを保存できない クライアント用(SPA) あとで説明 45

Slide 46

Slide 46 text

OpenID Connectとは? OAuthのグラントとOIDCのフロー 46 OAuth OIDC 認可コードグラント インプリシットグラント リソースオーナパスワード クレデンシャルグラント クライアント クレデンシャルグラント ハイブリッドグラント 認可コードフロー インプリシットフロー - - ハイブリッドフロー

Slide 47

Slide 47 text

OpenID Connectの流れを追ってみる 47

Slide 48

Slide 48 text

エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド OIDCの登場人物 48

Slide 49

Slide 49 text

エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド OIDCの登場人物 なんか見たことあるような …? 49

Slide 50

Slide 50 text

OAuth:リソースオーナー OIDC:エンドユーザー OAuth:クライアント OIDC:リライング・パーティ OAuth:認可サーバー OIDC:IDプロバイダ OAuth:リソースサーバー OIDC:UserInfoエンド OIDCの登場人物 Point ロールの呼び方が違うだけで、役割はOAuthと同じ! 50

Slide 51

Slide 51 text

① ② ③ ④ ①〜④ OAuthと全く同じ エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド 51

Slide 52

Slide 52 text

① ② ③ ④ ⑤ ⑤ アクセストークンと一緒にIDトークンを渡す エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド アクセストークン IDトークン 52

Slide 53

Slide 53 text

① ② ③ ④ ⑤ ⑥ IDトークンを検証し、ユーザーを認証する エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド IDトークンを検証 ⑥ 53

Slide 54

Slide 54 text

① ② ③ ④ ⑤ ⑥ IDトークンを検証し、ユーザーを認証する →ログイン完了! エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド IDトークンを検証 ⑥ 54

Slide 55

Slide 55 text

① ② ③ ④ ⑤ ⑦ ⑧ ⑦〜⑧(必要があれば) アクセストークンを使用してプロフィール情報を取得 例:名前、アイコン画像、その他個人情報 エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド ⑥ アクセストークン 55

Slide 56

Slide 56 text

IDトークンが なぜ必要なのか? 56

Slide 57

Slide 57 text

IDトークンとは? IDトークン » リライング・パーティがエンドユーザを認証するために使用 » 署名付きのJSON Web Token(JWT) » ユーザーIDや検証に必要な情報、署名などが含まれる 57

Slide 58

Slide 58 text

IDトークンとは? IDトークンの中身 » 誰が、いつ、どの範囲で、と言った(IdPから見た)一連の認証イベ ントしての情報が含まれている ⋄ ユーザーIDや検証に必要な情報、署名 ⋄ 発行日時、有効期限 ⋄ 許可された権限 58 適切に検証することで意図するやりとりが行われたことを確認 できる

Slide 59

Slide 59 text

IDトークンとは? IDトークンの中身 » 誰が、いつ、どの範囲で、と言った(IdPから見た)一連の認証イベ ントしての情報が含まれている ⋄ ユーザーIDや検証に必要な情報、署名 ⋄ 発行日時、有効期限 ⋄ 許可された権限 59 適切に検証することで意図するやりとりが行われたことを確認 できる Point!

Slide 60

Slide 60 text

不正ログイン を防ぐ仕組み 60

Slide 61

Slide 61 text

注意! IDトークン自体の具体的な検 証方法については触れません 61

Slide 62

Slide 62 text

nonceパラメータ » リプレイアタックを防ぐためのパラメータ » IDトークンに含まれる » 毎回異なるランダムな文字列を使用する 62

Slide 63

Slide 63 text

① ② ③ ④ ⑤ ⑦ ⑧ エンドユーザー リライング・パーティ IDプロバイダ UserInfoエンド ⑥ OpenID Connect 63

Slide 64

Slide 64 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ UserInfo ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 リダイレクト ②認証リクエスト 64

Slide 65

Slide 65 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト 65

Slide 66

Slide 66 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト 66 なんか違くない?

Slide 67

Slide 67 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト わかりやすくするために簡略化してました 67 なんか違くない?

Slide 68

Slide 68 text

nonceの使い方 68

Slide 69

Slide 69 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト ① セッションに紐付けてnonce=xyzを発行 nonce=xyz 69

Slide 70

Slide 70 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ② ② ② リダイレクトで認証リクエスト nonce=xyz 70

Slide 71

Slide 71 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ② ② ② nonceを認証リクエストに含める nonce=xyz nonce=xyz 71

Slide 72

Slide 72 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ③〜④ ③〜④ ● ID・パスワードの入力 ● ユーザ情報提供についての同意確認 nonce=xyz nonce=xyz 72

Slide 73

Slide 73 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ☆ ☆ ☆ 認証レスポンス(認可コード)を返す →認可コードはワンタイム(一度使用したら無効化) nonce=xyz 73

Slide 74

Slide 74 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ☆ ☆ = nonce=xyz IDプロバイダ上では認可コードとnonce=xyz は紐付けられている nonce=xyz 74

Slide 75

Slide 75 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑤ ⑤ ● 認可コードを使用してトークンをリクエスト ● アクセストークンやIDトークンを取得 nonce=xyz 75

Slide 76

Slide 76 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑤ = nonce=xyz nonce=xyzが設定されたIDトークンを返す nonce=xyz nonce=xyz 76

Slide 77

Slide 77 text

OpenID Connectのシーケンス図 ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ エンドユーザー リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑥ ⑥ nonceの値が一致するか検証 nonce=xyz nonce=xyz 77

Slide 78

Slide 78 text

OIDCで 入れ替えを 受けた場合 78

Slide 79

Slide 79 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ☆ ☆ nonce=xyz 認可コードを入れ替える場合 悪意あるユーザー 認可コードを入れ替え ちゃえ! 79

Slide 80

Slide 80 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ☆ ☆ 認可コードを入れ替える場合 悪意あるユーザー 認可コードを入れ替え ちゃえ! nonce=abc nonce=xyz 別のリライング・パーティで発行した認可コード →nonceが異なる 80

Slide 81

Slide 81 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑤ = nonce=abc 認可コードに紐づくnonceが含まれるIDトーク ンを返す nonce=abc nonce=xyz 悪意あるユーザー 認可コードを入れ替える場合 81

Slide 82

Slide 82 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑥ セッションに紐づくnonceと IDトークンのnonceが異なる! nonce=abc nonce=xyz 悪意あるユーザー 認可コードを入れ替える場合 82

Slide 83

Slide 83 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑥ セッションに紐づくnonceと IDトークンのnonceが異なる! nonce=abc nonce=xyz 悪意あるユーザー ログイン失敗! 認可コードを入れ替える場合 83

Slide 84

Slide 84 text

① ② ③ ④ リライング・パーティ IDプロバイダ ⑥ 補足:リプレイアタック対策 84 ⑤ エンドユーザー 一度使用した認可コードは無効化される (ワンタイム)

Slide 85

Slide 85 text

① ② ③ ④ リライング・パーティ IDプロバイダ ⑥ 補足:リプレイアタック対策 85 ⑤ エンドユーザー 通信が傍受され、使用済みの認可コードが盗 まれた場合 悪意あるユーザー

Slide 86

Slide 86 text

① ② ③ ④ リライング・パーティ IDプロバイダ ⑥ 補足:リプレイアタック対策 86 ⑤ 使用済みの認可コードの場合 既に無効化されているのでトークンは発行 されない 悪意あるユーザー

Slide 87

Slide 87 text

“アンチパターン” nonceを固定値にした場合 87

Slide 88

Slide 88 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ☆ ☆ 認可コードを入れ替える場合 悪意あるユーザー 認可コードを入れ替え ちゃえ! nonce=xyz nonce=xyz 異なるリライング・パーティでもnonceの値が固定 88

Slide 89

Slide 89 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑥ セッションに紐づくnonceと IDトークンのnonceが一致! nonce=xyz nonce=xyz 悪意あるユーザー 認可コードを入れ替える場合 89

Slide 90

Slide 90 text

ユーザ リライング・パーティ IDプロバイダ ①ログイン ③〜④認証 認可コード リダイレクト トークンリクエスト ⑤アクセストークン ・IDトークン ⑥IDトークン検証 ① ② ③ ④ ⑤ リライング・パーティ IDプロバイダ ⑥ リダイレクト ②認証リクエスト { ⑥ セッションに紐づくnonceと IDトークンのnonceが一致! nonce=xyz nonce=xyz 悪意あるユーザー 認可コードを入れ替える場合 不正ログイン成功! ぐへへ 90

Slide 91

Slide 91 text

OpenID Connectまとめ » クライアントが認証できるプロトコル » IDトークンを使用して安全に認証する » Nonceはランダムな文字列にし、必ず検証する » 認可コードをワンタイムにすることでリプレイアタックを防 ぐ 91

Slide 92

Slide 92 text

4. OIDCとネイティブアプリ 92

Slide 93

Slide 93 text

ネイティブアプリでのOIDC » client secretを秘匿に保てない ⋄ 認可コードフローだとトークン取得時に漏洩する ⋄ 自由に認可コードやトークンが発行可能に! » 長期間有効なAPIアクセスを必要とする リライング・パーティ IDプロバイダ 認証リクエスト (client_id, client_secret) 認証レスポンス (認可コード) 93

Slide 94

Slide 94 text

インプリシットフロー ClientSecretを安全に保存できないため、それを使用せず認可 コードフローを簡略化したフロー » クライアントの認証がIDプロバイダで行われない ⋄ client secretを使用せずにトークンの発行が可能 » リフレッシュトークンの発行が禁止 ⋄ 再取得時にはインプリシットフローを再度行う必要がある 94

Slide 95

Slide 95 text

インプリシットフローのシーケンス図 ユーザ リライング・パーティ IDプロバイダ UserInfo ログイン 認証 アクセストークン・IDトークン リダイレクト IDトークン検証 リダイレクト 認証リクエスト 95

Slide 96

Slide 96 text

シーケンス図の比較 ユーザ リライング・パーティ IDプロバイダ ログイン 認証 認可コード リダイレクト トークンリクエスト アクセストークン ・IDトークン IDトークン検証 リダイレクト 認証リクエスト ユーザ リライング・パーティ IDプロバイダ ログイン 認証 アクセストークン・IDトークン リダイレクト IDトークン検証 リダイレクト 認証リクエスト インプリシットフロー 認可コードフロー 96

Slide 97

Slide 97 text

シーケンス図の比較 ユーザ リライング・パーティ IDプロバイダ ログイン 認証 認可コード リダイレクト トークンリクエスト アクセストークン ・IDトークン IDトークン検証 リダイレクト 認証リクエスト ユーザ リライング・パーティ IDプロバイダ ログイン 認証 アクセストークン・IDトークン リダイレクト IDトークン検証 リダイレクト 認証リクエスト インプリシットフロー 認可コードフロー かなりシンプルに! 直接受け取るのが特徴 97

Slide 98

Slide 98 text

インプリシットフローの問題点 リソースアクセスと併用する場合 » IdPによってはアクセストークンの有効期限が切れるたびに再認証 が必要 ⋄ 数分〜数時間に一度ログイン画面が表示されてしまう →どうしてもユーザー体験が下がってしまう 98

Slide 99

Slide 99 text

インプリシットフローの問題点 リソースアクセスと併用する場合 » IdPによってはアクセストークンの有効期限が切れるたびに再認証 が必要 ⋄ 数分〜数時間に一度ログイン画面が表示されてしまう →どうしてもユーザー体験が下がってしまう 99 安全にリフレッシュトークンが 発行できればなー・・・

Slide 100

Slide 100 text

PKCE(ピクシー) » OAuthの拡張仕様 » パブリッククライアントで認可コードフローを安全に行 う仕組み ⋄ ClientSecretを安全に保存できないことへの対策 ⋄ 認可コードの横取り攻撃を防ぐ ⋄ 認可コードフローなので Refresh Tokenが取得可能 安全にリフレッシュトークンが取得できる! 100

Slide 101

Slide 101 text

パブリックとコンフィデンシャル » パブリッククライアント ⋄ クライアントの認証情報( ClientID, ClientSecret)をセキュアに保 存できないクライアント ⋄ ネイティブアプリやブラウザベースのアプリ » コンフィデンシャルクライアント ⋄ クライアントの認証情報をセキュアに保存できるクライアント ⋄ サーバーなど 101

Slide 102

Slide 102 text

認可コード横取り攻撃 » 以下のような場合、開発者が入れ替わりを防ぐのは困難 ⋄ 悪意のあるアプリが同時にインストールされている ⋄ 悪意あるアプリで同じカスタムスキームが設定されている ⋄ 悪意あるアプリがクライアント IDを知っている 102

Slide 103

Slide 103 text

認可コード横取り攻撃 » 以下のような場合、開発者が入れ替わりを防ぐのは困難 ⋄ 悪意のあるアプリが同時にインストールされている ⋄ 悪意あるアプリで同じカスタムスキームが設定されている ⋄ 悪意あるアプリがクライアント IDを知っている PKCEでの対策 入れ替わりが発生した場合、アクセストークンを発行させない 103

Slide 104

Slide 104 text

PKCE(ピクシー)での対策 以下の三つの値を使用して対策 » code_verifier ⋄ ランダムな文字列 » code_challenge ⋄ code_verifierにcode_challenge_methodを適応して算出した値 » code_challenge_method ⋄ plainまたはS256 104

Slide 105

Slide 105 text

認可コードフロー+PKCEのシーケンス図 ユーザ ネイティブアプリ ログイン 認証 カスタムスキームによるアプリ起動 (認可コード) IDトークン検証 認可リクエスト code_challenge code_challenge_method ブラウザ code_challenge code_challenge_method を保存 認可レスポンス (認可コード) アクセストークン ・IDトークン code_verifier検証 認可リクエスト code_challenge code_challenge_method IDプロバイダ(認可サーバー) トークンリクエスト 認可コード、code_verifier 105

Slide 106

Slide 106 text

認可コードフロー+PKCEのシーケンス図 ユーザ ネイティブアプリ IDプロバイダ(認可サーバー) ログイン 認証 カスタムスキームによるアプリ起動 (認可コード) IDトークン検証 認可リクエスト code_challenge code_challenge_method ブラウザ code_challenge code_challenge_method を保存 認可レスポンス (認可コード) アクセストークン ・IDトークン code_verifier検証 認可リクエスト code_challenge code_challenge_method トークンリクエスト 認可コード、code_verifier Step 1 code_challengeとcode_challenge_methodをIDプロバイダに保存 106

Slide 107

Slide 107 text

認可コードフロー+PKCEのシーケンス図 ユーザ ネイティブアプリ IDプロバイダ(認可サーバー) ログイン 認証 カスタムスキームによるアプリ起動 (認可コード) IDトークン検証 認可リクエスト code_challenge code_challenge_method ブラウザ code_challenge code_challenge_method を保存 認可レスポンス (認可コード) トークンリクエスト 認可コード、code_verifier アクセストークン ・IDトークン code_verifier検証 認可リクエスト code_challenge code_challenge_method Step 2 code_verifierをトークンリクエストに含める 107

Slide 108

Slide 108 text

認可コードフロー+PKCEのシーケンス図 ユーザ ネイティブアプリ IDプロバイダ(認可サーバー) ログイン 認証 カスタムスキームによるアプリ起動 (認可コード) IDトークン検証 認可リクエスト code_challenge code_challenge_method ブラウザ code_challenge code_challenge_method を保存 認可レスポンス (認可コード) トークンリクエスト 認可コード、code_verifier アクセストークン ・IDトークン code_verifier検証 認可リクエスト code_challenge code_challenge_method Step 3 事前に保存したcode_challengeと code_challenge_methodでcode_verifierを検証 108

Slide 109

Slide 109 text

認可コード 横取り攻撃を 受けた場合 109

Slide 110

Slide 110 text

認可コード横取り攻撃を受けた場合 ユーザ ネイティブアプリ ログイン 認証 カスタムスキームによるアプリ起動 (認可コード) IDトークン検証 認可リクエスト code_challenge code_challenge_method ブラウザ code_challenge code_challenge_method を保存 認可レスポンス (認可コード) アクセストークン ・IDトークン code_verifier検証 認可リクエスト code_challenge code_challenge_method IDプロバイダ(認可サーバー) トークンリクエスト 認可コード、code_verifier 悪意あるアプリ 横取りしたぜ! 110

Slide 111

Slide 111 text

認可コード横取り攻撃を受けた場合 ユーザ ネイティブアプリ ログイン 認証 カスタムスキームによるアプリ起動 (認可コード) IDトークン検証 認可リクエスト code_challenge code_challenge_method ブラウザ code_challenge code_challenge_method を保存 認可レスポンス (認可コード) アクセストークン ・IDトークン code_verifier検証 認可リクエスト code_challenge code_challenge_method IDプロバイダ(認可サーバー) トークンリクエスト 認可コード、code_verifier 悪意あるアプリ code_verifierがわか らない…ぐぬぬ 検証失敗! トークンレスポンスは無し 111

Slide 112

Slide 112 text

OIDCとネイティブアプリのまとめ » client secretを保存するのは厳禁 » 認証だけでいいならインプリシットフロー(非推奨) » UXを考えるなら認証コードフロー+PKCE(推奨) 112 Tips OAuth2.1ではインプリシットフローはなくなるので注意

Slide 113

Slide 113 text

5. OIDCとSPA 113

Slide 114

Slide 114 text

SPAでのOIDC SPA(ブラウザ)では安全にアクセストークンやIDトークンが保存 できない » Web Storage(localStorageやsessionStorage)に保存 ⋄ 自分のアプリでXSS対策をしても他のJSが悪さをすると台無し » iFrameでIdPとのセッションをメモリ上に格納 ⋄ サードパーティCookieを保持するのはNGな流れになってきた →今のところベストプラクティスはない 114

Slide 115

Slide 115 text

SPAでのOIDC 二つの対策 » 認可コードフロー+独自のセッション » RefreshTokenをローテーションする(Auth0など) 115

Slide 116

Slide 116 text

認可コードフロー+独自セッション 116

Slide 117

Slide 117 text

認可コードフロー+独自セッション » OIDCをログイン管理に使用しない ⋄ 認証のみに使用する ⋄ 独自のセッション(cookieなど)でログイン管理を行う フロント ネイティブアプリ IDプロバイダ バックエンド 認可コード トークンリクエスト アクセストークン IDトークン 独自セッション 117

Slide 118

Slide 118 text

ユーザ リライング・パーティ フロント IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 独自セッション nonceやcode_challengeを生成 118

Slide 119

Slide 119 text

ユーザ リライング・パーティ フロント IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 独自セッション Point 1 フロントとバックエンドであらかじめセッションを構築 →バックエンドでnonceやPKCEに必要な値を生成し、セッションに紐づ ける nonceやcode_challengeを生成 119

Slide 120

Slide 120 text

ユーザ リライング・パーティ フロント IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 独自セッション Point 2 認可コードをバックエンドにリクエストする nonceやcode_challengeを生成 120

Slide 121

Slide 121 text

ユーザ リライング・パーティ フロント IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 独自セッション Point 3 バックエンドでトークンを取得 nonceやcode_challengeを生成 121

Slide 122

Slide 122 text

ユーザ リライング・パーティ フロント IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 独自セッション Point 4 セッションに紐づくnonceやcode_verifierで検証する 必要であればこのタイミングでUserInfoからプロフィール情報を取得の する nonceやcode_challengeを生成 122

Slide 123

Slide 123 text

ユーザ リライング・パーティ フロント IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 独自セッション Point 5 以後全てセッションで管理する アクセストークンやIDトークンはフロントに一切渡らない nonceやcode_challengeを生成 123

Slide 124

Slide 124 text

認可コードフロー+独自セッション まとめ » フロントにトークン類を保持しないのでセキュア ⋄ セッションにユーザー IDなどの識別子を含めないように注意 ⋄ CSRF対策も忘れずに » SPAとネイティブアプリを同時に使用する場合はバックエン ドの実装を分ける必要がある » 実装が割と手間 124

Slide 125

Slide 125 text

RefreshTokenのローテーション 125

Slide 126

Slide 126 text

RefreshTokenをローテーションする » RefreshTokenを使用して新しいトークンを発行する時 ⋄ →古いRefreshTokenは無効化&新しいRefreshTokenを発行 ⋄ OAuthの仕様だと自動では無効化されない » 古いRefreshTokenでアクセスされた場合、全てのRefreshTokenを無 効化 » IdP側に仕組みが必要(Auth0などがサポート) 126

Slide 127

Slide 127 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン 通常のトークンリフレッシュ 127

Slide 128

Slide 128 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン 通常のトークンリフレッシュ 悪意あるユーザー 使用済みのリフレッシュトークン 横取りしたぜ! 128

Slide 129

Slide 129 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン 通常のトークンリフレッシュ 悪意あるユーザー 無効化されてないからア クセスし放題! 2回目以降は新しいリフレッ シュトークンを使用する 129

Slide 130

Slide 130 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン Auth0のトークンリフレッシュ 古いリフレッシュトークン を無効化 130

Slide 131

Slide 131 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン Auth0のトークンリフレッシュ 悪意あるユーザー 使用済みのリフレッシュトークン 横取りしたぜ! 131

Slide 132

Slide 132 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン Auth0のトークンリフレッシュ 悪意あるユーザー 無効化されてるからトーク ンを更新できない… 既に無効化されてるリフレッ シュトークンが使用された! 132

Slide 133

Slide 133 text

クライアント (SPA) 認可サーバー (Google OAuth) RefreshTokenのローテーション リフレッシュトークン 新しいアクセストークン 新しいIDトークン 新しいリフレッシュトークン Auth0のトークンリフレッシュ 悪意あるユーザー 無効化されてるからトーク ンを更新できない… 既に無効化されてるリフレッ シュトークンが使用された! トークンが漏洩している可能性あり! 未使用のリフレッシュトークンも無効化! 133

Slide 134

Slide 134 text

RefreshTokenのローテーション まとめ » リフレッシュトークンを盗難されても被害を最小限にとどめ る » IdP側での実装が必要 » トークンを盗まれるの自体は防げない ⋄ トークンの有効期限を短くすることで対策 134

Slide 135

Slide 135 text

OIDCとSPAのまとめ » SPAでトークンを安全に保管する方法は今のところ存在し ない » OIDCを認証として使用し、独自のセッションでログイン管理 を行う(推奨) » RefreshTokenをローテーションする(Auth0など) 135

Slide 136

Slide 136 text

6. おまけ ハイブリッドフロー 136

Slide 137

Slide 137 text

ハイブリッドフロー » ハイブリッドフロー ⋄ 認可コードフローとインプリシットフローを合わせたもの ⋄ 認可レスポンスとトークンレスポンスの両方があるのが特徴 フロント ネイティブアプリ IDプロバイダ バックエンド 認可コード トークンリクエスト アクセストークン IDトークン 認証完了 137 認証リクエスト 認可コード・アクセストークン

Slide 138

Slide 138 text

ユーザ リライング・パーティ ネイティブアプリ IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ・アクセストークン) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 認証完了 138

Slide 139

Slide 139 text

ユーザ リライング・パーティ ネイティブアプリ IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ・アクセストークン) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 認証完了 139 Point 1 認可コードとアクセストークンを受け取る。 アクセストークンはネイティブアプリ側に保存

Slide 140

Slide 140 text

ユーザ リライング・パーティ ネイティブアプリ IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ・アクセストークン) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 認証完了 140 Point 2 認可コードをバックエンドにリクエストする

Slide 141

Slide 141 text

ユーザ リライング・パーティ ネイティブアプリ IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ・アクセストークン) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 認証完了 141 Point 3 バックエンドでセキュアにトークンを取得可能

Slide 142

Slide 142 text

ユーザ リライング・パーティ ネイティブアプリ IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ・アクセストークン) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 認証完了 142 Point 4 IDトークンを検証する

Slide 143

Slide 143 text

ユーザ リライング・パーティ ネイティブアプリ IDプロバイダ UserInfo リライング・パーティ バックエンド ログイン 認証 認証レスポンス(認可コード ・アクセストークン) リダイレクト 認可コード トークンリクエスト アクセストークン ・IDトークン IDトークン検証 認証完了 143 Point 5 アクセストークンを保存しているため、 ネイティブ側からもリソースにアクセスが可能となる

Slide 144

Slide 144 text

ハイブリッドフローのまとめ » 認可コードフローとインプリシットフローを合わせたもの ⋄ 認可レスポンスとトークンレスポンスの両方があるのが特徴 » バックエンド側でセキュアに認証が可能 » パブリック(ネイティブアプリ)側からリソースにアクセスすることが 可能 144

Slide 145

Slide 145 text

Last. まとめ 145

Slide 146

Slide 146 text

今日の話 まとめ » OAuthの概要 » OAuth認証はNG » OpenID Connectの検証はしっかりと行う » ネイティブアプリとSPAでのOIDCの注意点 146

Slide 147

Slide 147 text

“IDトークンを検証したからといって 安全になるわけではありません。” “OpenID Connectを正しく理解して使用しましょう。” 147

Slide 148

Slide 148 text

Special Thanks! Auth屋 ● 書籍:雰囲気でOAuth2.0を使っているエンジニアが OAuth2.0 を整理して、手を動かしながら学べる本 ● 書籍:OAuth、OAuth認証、OpenID Connectの違いを整理して 理解できる本 ritou ● ブログ:r-weblife 148

Slide 149

Slide 149 text

Thank you watching! 遠藤 大輔 Twitter: @DddEndow 149