OAuth 2.0でのHolder-of-Key TokenとKeycloakについて

# OAuth 2.0でのHolder-of-Key TokenとKeycloakについて

## はじめに

日立製作所の@tnorimatと申します。OAuth 2.0でのHolder-of-Key Tokenについて、コンセプトとその実現方式、そしてKeycloakへのパッチ投稿と実装について記します。

**Notes: 本投稿の内容は、公開情報を元に独自に解釈したものです。**

## Holder-of-Key Tokenについて

OAuthで使われているトークン類は、多くの場合Bearer Token(ベアラトークン)です。Bearer Tokenでは、トークンの所持者以外の第三者でもトークンを行使できるという課題がありました。これに対しHoler-of-Key Tokenではトークンの所持者以外の第三者がトークンを行使しようとした場合これを検知できます。具体的には、Holder-of-Key Tokenとは下記のようなものです。

- トークンの所持者証明が行える形式のトークン。
- 所持者証明を行うために、公開鍵暗号アルゴリズムを使用する。
- “Holder-of-Key”＝鍵の所持者 であるが、ここでのKeyとは公開鍵暗号アルゴリズムでの秘密鍵（非公開鍵）を指す。
- “Proof-of-Possession”という言い方もされている。

## OAuth 2.0でのHolder-of-Key Tokenが必要とされるシーン
高いセキュリティ水準が要求されるAPIサービスがあげられます。例えば以下の仕様で必要とされています。

- [Financial API - Part 2: Read and Write API Security Profile](http://openid.net/specs/openid-financial-api-part-2.html)

Financial APIとは、OpenID Foundationが策定している金融業界向けのAPI仕様のことです。

## OAuth 2.0でHolder-of-Keyの対象となるToken
OAuth 2.0において、Holder-of-Keyの対象となりえるトークンは、認可コード、アクセストークン、リフレッシュトークンとなります。

## OAuth 2.0でHolder-of-Key Tokenを実現する方式

実現方式はいろいろあります。前述のFinancial API Part 2の仕様では、以下2つの方法が挙げられています。

- [MTLS] : [OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-mtls-09)
- [OAUTB]：[OAuth 2.0 Token Binding](https://tools.ietf.org/html/draft-ietf-oauth-token-binding-07)

双方の仕様ともまだInternet Draftの段階であるため、今後内容が変わる可能性があることにご注意ください。
  
  
双方の方法の特徴を以下に示します。

- [MTLS]は既存の技術（TLS、クライアント証明書）をそのまま利用するのに対して、[OAUTB]は独自のTLS拡張を必要とします。
- 所持証明の対象は、[MTLS]ではクライアント証明書に対応する秘密鍵（非公開鍵）であり、[OAUTB]では、Token Binding IDというデータ構造に対応する秘密鍵（非公開鍵）となります。
- 所持証明の方法は、[MTLS][OAUTB]ともに、公開鍵暗号アルゴリズムを利用したディジタル署名とその検証となります。
- 「鍵の所持＝トークンの所持」とするために、[MTLS]ではクライアント証明書をトークンと「バインド」し、[OAUTB]ではToken Binding IDというデータ構造をトークンと「バインド」します。
- 「バインド」とは、対象となる2者に関係があることを検証できるための処理を施すことです。


## Holder-of-Key Tokenの効果

前述のとおり、Holder-of-Key Tokenをもちいることで、第三者によるトークンの行使を検知することができます。これについては、OAuth2.0のセキュリティのベストプラクティスである[OAuth 2.0 Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-06)の[2.2.  Token Replay Prevention](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-06#section-2.2)で記されており、その対策が[3.7.1.2.  Sender Constrained Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-06#section-3.7.1.2)で述べられています。
  

例えば、攻撃者が被害者のトークンに加えてクライアント証明書やToken Binding IDを盗聴でき、それを用いてトークンを行使しようとしたとします。

[MTLS]では、TLSハンドシェイク時クライアント証明書を用いたクライアント認証を行うことになっています。この際このクライアント証明書に対応する秘密鍵で、TLSハンドシェイクで交わされたメッセージのダイジェストに対しディジタル署名を行う必要があります。攻撃者は秘密鍵まで盗聴できていないので、これを実施できません。

[OAUTB]では、トークン送信時にToken Binding IDを含むToken Binding Messageを同時に送る必要があります。この際Token Binding IDに対応する秘密鍵で、あるデータ(Exported Keying Material、etc...)にディジタル署名を行う必要があります。攻撃者は秘密鍵まで盗聴できていないので、これを実施できません。

## どちらの方法が良いのか

適用の容易さという観点からは、[MTLS]が良いと考えます。

プライバシー保護の観点からは、[OAUTB]が良いと考えます。

[MTLS]では、クライアント証明書とトークンがバインドされます。そのため、このトークンを受け取ったサーバーが裏でアクセス情報を共有すると、あるクライアント証明書の所持者がどこにアクセスしたかがわかってしまう恐れがあります。OAuth 2.0のPublicなクライアントの内ユーザーのデバイス上で動作するアプリケーションについて、場合によってはクライアント証明書の所持者すなわちデバイスのユーザーの関係ができかねません。これについては、[Financial API - Part 2: Read and Write API Security Profile](http://openid.net/specs/openid-financial-api-part-2.html)の[9.  Privacy Considerations](http://openid.net/specs/openid-financial-api-part-2.html#privacy-considerations)で触れられており、ユーザーのデバイス上で動作するPublicなクライアントは、[OAUTB]を適用するべきとあります。

[OAUTB]では、Token Binding IDとトークンがバインドされます。Token Binding IDはアクセス先のサーバーごとに異なるものを使用することができるため、このような問題は起きないであろうと考えます。ただし、トークンの送受信者すべてが[OAUTB]固有のTLS拡張に対応する必要があり、この点を鑑みると[MTLS]の方が適用が容易であると考えます。

## OAuth 2.0でのHolder-of-Key Tokenの実装例

オープンソース・ソフトウェアである[keycloak](https://www.keycloak.org/)で、OAuth 2.0でのHolder-of-Key Tokenの実装がされています。バージョン[4.0.0.Final](https://www.keycloak.org/docs/4.0/release_notes/index.html)から「OAuth 2 Certificate Bound Access Tokens」という名称で、この機能が入っています。
この実装は筆者が作成したものであり、そのPull Requestは、[https://github.com/keycloak/keycloak/pull/5083](https://github.com/keycloak/keycloak/pull/5083) となります。

この実装では、[MTLS]の方法でHolder-of-Key Tokenを実現しています。Holder-of-Key Tokenの対象となっているトークンは、アクセストークンとリフレッシュトークンです。

このHolder-of-Key Tokenの適用方法は以下となります。

### keycloakが動作するAPサーバーであるWildflyをMutual SSL(TLS)に対応させる

[MTLS]の方式では、TLSハンドシェイク時にクライアント証明書の提示を必要とします。
keycloakのドキュメント[Server Administration Guide - 6.6.2. Enable X.509 Client Certificate User Authentication](https://www.keycloak.org/docs/latest/server_admin/index.html#enable-x-509-client-certificate-user-authentication)の、Enable mutual SSL in WildFlyの節を参照ください。

### クライアント単位でHolder-of-key Tokenを有効にする

keycloakでは、クライアント単位でHolder-of-Keyの有効・無効を設定できます。デフォルトでは無効となっています。
keycloakのドキュメント[Server Administration Guide - 8.1.1. Advanced Settings](https://www.keycloak.org/docs/latest/server_admin/index.html#advanced-settings)の、OAuth 2.0 Mutual TLS Client Certificate Bound Access Tokenの節を参照ください。

### 有効性の検証
先ほどの[Pull Request](https://github.com/keycloak/keycloak/pull/5083)の中に有効性の検証コードが入っています。証明書が違う場合にアクセスを拒否するようになっています。
4.0.0のテストコードの、[refreshTokenRequestByHoKRefreshTokenByOtherClient](https://github.com/keycloak/keycloak/blob/4.0.0.Final/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/hok/HoKTest.java#L256)という箇所にてチェックしています。


## 参照文献

### Holder-of-Key Tokenを利用する仕様：
- [Financial API - Part 2: Read and Write API Security Profile](http://openid.net/specs/openid-financial-api-part-2.html)

### [MTLS]に関するもの：
- [OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-mtls-09)

### [OAUTB]に関するもの：
- [RFC 5705 Keying Material Exporters for Transport Layer Security (TLS)](https://tools.ietf.org/html/rfc5705)

Token Binding IDに対応する秘密鍵の署名対象となるデータのひとつであるExported Keying Materialについてです。

- [The Token Binding Protocol Version 1.0](https://tools.ietf.org/html/draft-ietf-tokbind-protocol-19)

Token Bindingで使用されるデータと処理方法について記されています。

- [Transport Layer Security (TLS) Extension for Token Binding Protocol Negotiation](https://tools.ietf.org/html/draft-ietf-tokbind-negotiation-13)

TLSハンドシェイク時に交わされるメッセージの拡張領域を使用し、Token Bindingで使用される処理方式・パラメータなどをネゴシエーションする方法について記されています。

- [Token Binding over HTTP](https://tools.ietf.org/html/draft-ietf-tokbind-https-17)

上述のToken Bindingを、HTTP上で実現するための方法が記されています。

- [OAuth 2.0 Token Binding](https://tools.ietf.org/html/draft-ietf-oauth-token-binding-07)

上述のToken Bindingを、OAuth 2.0のトークンに適用するための方法が記されています。

### [MTLS][OAUTB]に共通のもの：
- [RFC 7800 Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs)](https://tools.ietf.org/html/rfc7800)

秘密鍵に対応する共通鍵と、トークンとを「バインド」するために、共通鍵の情報をトークンに封じる際に使用されるフォーマットについて記されています。

- [OAuth 2.0 Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-06)

OAuth 2.0のセキュリティに関するベストプラクティスです。