lasciva blog

開発して得た知見やwebビジネスのストック

「OAuth徹底入門 セキュアな認可システムを適用するための原則と実践 」を読んだ

OAuth徹底入門 セキュアな認可システムを適用するための原則と実践

OAuth徹底入門 セキュアな認可システムを適用するための原則と実践

目的、モチベーション

  • OAuthの仕組みを雰囲気でしか理解していなかったので、理解を深めるため。
    • 普通の認可と違い、何故セキュアなのか。
  • アプリケーションにSNS認証を導入する際に、どのように導入すればセキュアなのかを理解するため。

全体の感想

読み進めていくうちに、OAuthは認証プロトコルではなく移譲プロトコルであるというのが特に衝撃的で、OAuthのことを全く理解していなかったんだなと思った。
実際にコードを書いて簡単だが一連のやり取りを把握できたのが良かった。
また、何故このパラメータがないと脆弱性につながるのかなども詳しく説明してあり、理解も深まりやすかった。
入門書レベルだとは思うがボリュームもあり、OAuthを雰囲気で使っている人にはオススメ。

目次

概要

github.com

英語版はこちら

OAuth 2 in Action

OAuth 2 in Action

  • 作者:Justin Richer,Antonio Sanso
  • 出版社/メーカー: Manning Publications
  • 発売日: 2017/03/18
  • メディア: ペーパーバック

第1章 OAuth 2.0とは何か?そして、なぜ気にかけるべきなのか?

OAuth2.0とは何か?

委譲プロトコルで、アプリケーション(twitterなど)のリソースの所有者に認可されるように許可を求めて、クライアント(twitterのデータを利用しているサービスなど)トークンによって所有者の代わりにアクセスできるようにする仕組み。
認可プロセスや暗号の方法などは定義しておらず、必ず認証がある訳ではなく、認証プロトコルでもない。

クレデンシャルの共有の問題点

  • クライアントが繰り返しパスワードを使うために、平文や可逆暗号でパスワードを保存してしまう
  • クライアントに与えるべきでない権限も付与してしまう

第2章 OAuthダンス - OAuthの構成要素間の相互作用

2.1 OAuth 2.0プロトコルの概要~トークンの取得と使用~

標準的な流れは以下の通り。

  1. リソース所有者はクライアントにリソース所有者の代わりとして振る舞ってほしいことを指示する
  2. クライアントは認可サーバにリクエストをし、そこでリソース所有者にクライアントを認可するかどうかの判断を行わせる
  3. こうすることで、クライアントはクレデンシャルを知らないで済む
  4. リソース所有者はクライアントを許可する
  5. クライアントは認可サーバからトークンを受け取る
  6. クライアントは保護対象リソースにトークンを提示する
2.2 OAuth 2.0における認可付与の詳細

認可コードによる付与(Authorization Code Grant)では、一時的なクレデンシャルである認可コードを使い、トークンを取得する。

  1. リソース所有者がクライアントを許可すると、認可コードとともにクライアントにリダイレクトされる
  2. クライアントは受け取った認可コードを、クライアント自身のクレデンシャルとともに認可サーバに送る
  3. 認可サーバは、認可コードのクライアントと、クレデンシャルのクライアントが一致した場合にトークンを返す(認可コードはrevokeされる)
2.4 トークン、スコープ、認可付与

アクセス・トーク
中身のないただの文字列で、クライアントは内容を知らずに扱うことができる。

スコープ
スペースで区切られた、保護対象リソースでの権限。

リフレッシュ・トーク
新しいアクセス・トークンを取得するのに必要なトークン。アクセス・トークンの期限が切れても、リソース所有者の認証を再度求めずに取得できる。

認可付与
OAuthのプロトコルを介して、アクセス権をクライアントが得る手段、即ちトークンを取得するフローのこと。

2.5 OAuthの構成要素間のやり取り

バック・チャネル・コミュニケーション
リソース所有者やブラウザ以外の、認可サーバやクライアント、保護対象リソースのHTTPのコミュニケーションのこと。

フロント・チャネル・コミュニケーション
サーバとの、ブラウザを介したコミュニケーションのこと。ブラウザを介すため、機密情報は渡らない方がベター。

第3章 シンプルなOAuthクライアントの構築

第4章 シンプルなOAuthの保護対象リソースの構築

第5章 シンプルなOAuthの認可サーバの構築

この3つの章は、サンプルコードを元に実際に簡易なサーバを実装していった。手を動かすとイメージがつかめて良かった。
気になったのは下記。

  • stateパラメータははcallbackを直接叩かれ乗っ取りをされかけたときの防止策
  • Bearerは規約的には大文字小文字は区別しない

第6章 実際の環境におけるOAuth 2.0

6.1 認可における付与方式

6.1.1 インプリシット付与方式

この付与形式では、認可エンドポイントから直接トークンを得る。

クライアントがブラウザ内部に埋め込まれたJavaScriptアプリケーションのような場合、認可コードによる付与を行う際に、認可コードをクライアントに返すとブラウザに認可コードが渡ってしまいクライアント以外も知ってしまうため、メリットがない。
ブラウザアプリケーションの場合、ユーザがいるためトークンが無効になっても再度認証を求められるため、TOFUも維持できる。

6.1.2 クライアント・クレデンシャルによる付与方式

バックエンドの認証などで、リソース所有者が明確に存在しなかったり、クライアント自体がリソース所有者の場合、この付与方式を用いる。
scopeなどを指定して、認可エンドポイントから直接トークンを得る。

6.1.3 リソース所有者のクレデンシャルによる付与方式

リソース所有者のクレデンシャルをクライアントに送り、それを使って認可サーバからアクセストークンを得る方法。
クライアントにクレデンシャルが渡り、アンチパターンなのでできれば避けるべき。

第7章 よく狙われるクライアントの脆弱性

7.2 クライアントに対するCSRF攻撃

仕様ではstateパラメータは必須でないが、CSRF攻撃を防ぐために検証した方が良い。

7.3 クライアント・クレデンシャルの不当な取得

ネイティブ・アプリケーションなどは、デコンパイルされる可能性が0ではないため、クレデンシャルは動的に取得するようにして、各デバイス毎にクライアントIDを管理した方が安全。

7.4 リダイレクトURIの登録

リダイレクトURIは攻撃されやすく、バグも発生しやすいので、完全一致で検証するのがベスト。
サブディレクトリを検証しない場合、CGM型のサイトなどでユーザがページを作成できるときなどに、そのURLを指定されると漏洩の元になる。

  • HTTPリファラー: URLのパラメータにcodeが付与された状態で、攻撃者のページにリダイレクトした場合、imgやscriptを攻撃者のサイトにリクエストすることで、リファラー中のURLから盗まれる。
  • オープンリダイレクト: パラメータの値のURLを検証せずに、そのURLにリダイレクトしてしまうこと。URIフラグメントにトークン情報を含めた状態でリダイレクトすると盗まれる。
7.6 トークンの不正な取得

Authorizationヘッダを利用できず、URLのパラメータに含める場合は攻撃されやすくなるので、注意が必要。

  • access.logなどにパラメータとして書き出される
  • オンライン掲示板などに、ユーザが意図せず貼ってしまう
  • リファラーヘッダにトークンが含まれる

第8章 よく狙われる保護対象リソースの脆弱性

8.2 保護対象リソースのエンドポイントの設計

HTTPヘッダを適切に設定すれば、XSS対策をより安全に行える。

ヘッダ 説明
Content-Type jsonを指定することで、ブラウザがXSSから保護する
X-Content-Type-Options MIMEスニッフィングを防ぐ。
X-XSS-Protection 自動的にXSS攻撃を除外
8.3 トークンのリプレイ攻撃

OAuth2.0ではTLSが前提となっているが、HSTS(HTTP Strict Transport Security)を使えば、サーバ側で安全なHTTPSのみを使うように宣言できる。
使い方は、レスポンスのヘッダに Strict-Transport-Securityを設定する。

第9章 よく狙われる認可サーバの脆弱性

  • 認可コード
    • 一度使われたら、破棄する(URLに含まれるため、ブラウザの履歴などに残ってしまう可能性がある)
    • クライアントが一致するか確認する
  • リダイレクト
    • 絶対に、何の検証もなしにリダイレクトしないこと
    • バグの元なので、redirect_uriは極力完全一致するか検証する
    • エラーを返す際にも、Refererヘッダなどを介して情報漏洩しないように注意する

第10章 よく狙われるOAuthトークンの脆弱性

トークンはシンプルである一方で、盗まれた際には何でもできてしまうため、工夫が必要。

  • 盗まれないように保護
  • 盗まれてしまった際の被害を小さくする
    • クライアント: 必要最低限のscopeのトークンを要求する
    • 認可サーバ: 有効期限を短くする
  • サーバを攻撃されてしまった際の被害を小さくする
    • 認可サーバ: トークンをハッシュ値で保存する
    • リソースサーバ: キャッシュする場合は、一時的なメモリを使用する

第11章 OAuthトーク

11.1 OAuthにおけるトークンとは何か?

OAuthでは、トークンの形式は定められていない。

よく用いられる乱数のトークンは、サイズを小さく保ちつつ、文字列を更に乱雑にすることでセキュアにできる。その一方で、認可サーバと保護対象リソースとの間でデータソースを共有できない場合は、通信処理がボトルネックになったりするなどのデメリットもある。

11.2 JWT(JSON Web Token)

トークンそのものに、必要な情報を詰め込んだものの例として、JWTが紹介されていた。
内部に情報を持つことで、認可サーバを介さずにリソースサーバがトークンの有効性やスコープを確認することができる。

11.2.1 JWTの構造
.で区切られた3つのパート(header, payload, verify signature)の文字列から成る。文字列はJSONオブジェクトをBase64エンコードされている。
トークンが盗まれた場合、デコードされるとpayloadの情報が読み取れてしまうので、HTTPSを使いかつ機密情報はトークンに含めないこと。
Base64エンコードされているのは、トークンを受け渡してる間にエンコードされてしまったり(URLのパーセントエンコーディングなど)して、処理を煩雑にしないための工夫である。

11.3 JOSE(JSON Object Signing and Encryption)

JWTでは、署名のアルゴリズムを指定することができる。
例として、RS256を使うと秘密鍵を認証サーバで管理して、公開鍵をリソースサーバが受け取り検証することでセキュアに検証できる。

トークン内の情報を暗号化するためにJWE(JSON Web Encryption)という仕組みもある。

11.4 トークン・イントロスペクション(Token Introspection)

トークン自身に情報を持たせると、scopeを最新の状態に更新できないなどのデメリットもある。 それを解決する一つが、Token Introspection。 認可サーバに /introspectのようなエンドポイントを用意し、tokenの詳細の情報を取得できるようにして解決するプロトコルである。
ただし、リクエスト数が増えて認可サーバに負荷がかかるので、リソースサーバ側でキャッシュするなどの工夫が必要。

11.5 トークン取り消し(Token Revocation)

ユーザがログアウトしたなど、クライアントが能動的にトークンを無効にしたい場合には、Token Revocationを利用する。
単にアクセストークンとリフレッシュトークンを無効にするだけだが、攻撃されないように、トークンのクライアントとリクエストしてきたクライアントが一致するかの検証を行い、無効であったとしても201を返すこと。401を返すとDoS攻撃が行われ、他のクライアントでトークンが有効であることがわかってしまう。

第12章 動的クライアント登録(Dynamic Client Registration)

スケーラビリティを確保し、クライアントとの信頼関係を築くために動的にクライアントの管理を行いましょうという話だった。

第13章 OAuth2.0を使ったユーザ認証

OAuth 2.0自身は認証プロトコルでないが、認証プロトコルを構築するために用いられることもある。
その例として、OpenID Connectが紹介されていた。

第14章 OAuth2.0を使うプロトコルとプロファイル

OAuth2.0を拡張したプロトコルやプロファイルが紹介されていた。

14.1 UMA(User Managed Access

三者に自分のリソースの利用をクライアントで利用するのを許可する(ex. Aliceが自身のリソースの利用を、Bobに利用許可するとき)を安全に管理するために、UMA(User Managed Access)が利用できる。
UMAでは、自分のリソースポリシーを設定し、Aliceを介さずにトークンを取得できる。また、トークンも第三者である利用者毎に発行できるため、revokeなどの処理も行える。

処理の流れとしては、通常のOAuthに加えて、リソース所有者がポリシーを先に設定し、リソースサーバはトークンが有効な権限を持つか検証しないといけない。

14.2 HEART(HEAlth Relationship Trust)

OAuthは柔軟な反面、相互運用性や互換性の確保が難しい。医療分野などの単一分野を取り扱っている場合、共通のAPIを利用することがよくあり、サーバ同士が連携しやすいように、ガイドラインが利便性が高まる。
その一例として、HEART(HEAlth Relationship Trust)が紹介されていた。

14.3 iGov(international Government assurance)

HEARTと同じように、行政機関で使われることを目指すiGov(international Government assurance)が紹介されていた。
行政機関のシステムは、長期間使用される一方で、システムのアップデートが遅くなったりする傾向もあるため、互換性が担保できるように慎重に策定する必要がある。

第15章 Bearerトークンの次のもの

Bearerトークンはシンプルなため、トークンを奪われると再利用されてしまう。
よりセキュアな所有証明(Proof of Possession:PoP)トークンと、TLSトークン・バインディングが紹介されていた。

OAuth徹底入門 セキュアな認可システムを適用するための原則と実践

OAuth徹底入門 セキュアな認可システムを適用するための原則と実践