TLS (旧SSL)

mutual-TLS(mTLS, 2way TLS)相互認証の仕組み ~クライアント認証とトークンバインディング over http

mutual-TLS とは ~ mTLS と TLS の違い~

一般の Web サイト、例えば google.co.jp や yahoo.co.jp 等にアクセスする際には https というプロトコルが使われます。

これは http プロトコルを TLS というセキュリティプロトコルで保護する、ごく一般的なアクセス方法です。

TLS ではセキュリティ機能として「通信暗号化」の他に「通信相手の認証」を行っています。具体的には Web サーバから提示されるサーバ証明書について以下を調べます。

  • 証明書にあるデジタル署名は信頼できるか?
  • 相手はサーバ証明書の対となる秘密鍵を持っているか?

前述の google.co.jp や yahoo.co.jp 含め、多くの Web サーバへの https アクセスにおいて、認証はサーバ側のみに対して行います。

ですが TLS の規格としてはオプションでクライアント側の認証を行うことができます。このような仕組みを mutual-TLS (mTLS あるいは 2way TLS) と呼びます。

下図において、左側が「クライアント認証の無い、一般的な TLS」で、右側が「クライアント証明書によるクライアント認証のある、Mutual-TLS」です。

RFC8705 での mutual-TLS に関する説明

RFC8705 の Section1.2 では mutual-TLS の言葉の定義が以下のように記載されています。

the term "mutual TLS" refers to the process whereby, in addition to the normal TLS server authentication with a certificate, a client presents its X.509 certificate and proves possession of the corresponding private key to a server when negotiating a TLS session.

日本語訳すると以下のようになります。

"mutual-TLS" という言葉は、TLSのネゴシエーションの際に、サーバ証明書による通常の TLS サーバ認証に加えて、クライアントが自分の X.509 証明書 (クライアント証明書) を示し、その証明書に対応する秘密鍵所持をサーバへ示すプロセスのことです。

Mutual-TLS に関する RFC を探すと、この RFC8705 が目立つ順位でヒットするのですが、ただ、この RFC8705 では単純な Mutual-TLS の話ではなく、それにまつわる「Certificate Bound Access Token」の話がメインとなっています。サーバ側で http レイヤのアクセストークンを TLS レイヤのクライアント証明書と紐づけ、認証をより強固に行う技術です。

RFC8705 の Mutual-TLS Client Authentication と Mutual-TLS Certificate-Bound-Access Tokens

RFC8705 Section1 には以下のように記載されています。

Mutual-TLS certificate-bound access tokens and mutual-TLS client authentication are distinct mechanisms that are complementary but don't necessarily need to be deployed or used together.

日本語訳。

"Mutual-TLS Certificate-Bound-Access-Token" と "Mutual-TLS Client Authentication は、補完的な別個のメカニズムですが、必ずしも一緒に展開または使用する必要はありません。

つまり、「Mutual-TLS のクライアント証明書とアクセストークン紐付けの話」と「Mutual-TLS クライアント証明書によるクライアント認証の話」は、互いに関連はするけど完全に別物だよ、と言っています。

後者の Mutual-TLS Client Authentication は先程の Mutual-TLS の定義と同じ意味です。つまり、サーバとクライアントが互いに証明書を提示し合い、互いを認証し合うプロセスのことです。

一方、前者の Mutual-TLS Certificate-Bound-Access-Token は、ことさら OAuth2 に特化して、Mutual-TLS で使う「TLS クライアント証明書」と認可サーバ「OAuth2 アクセストークン」を結び付け、アクセストークンの不正利用を防ごう、という仕組みについて記載しています。

OAuth2 の特殊な点としてクライアントは認可サーバからアクセストークンを払い出され、そのアクセストークンを使って OAuth2 対応 Web サーバ (リソースサーバ) へアクセスします。(例えば『Facebook でログイン』とあった場合、認可サーバは facebook で、リソースサーバはログイン先の Web サーバです)

リソースサーバはアクセストークンによってユーザを識別し、そのユーザに応じて表示させる内容を変えたり、閲覧できる範囲を限定したりします。

Bearerトークンとトークンバインディング

近年では OAuth2 以外にも、Web サービスへの SSO (シングルサインオン) として SAML など様々な Federation タイプの技術が使われています。

これらの SSO 技術では認証や認可サーバから「アクセストークン (あるいはセキュリティトークン)」が発行され、このトークンを連携先の Web サーバで提示すれば Web サービスが使えるようになります。

また、http にはログイン情報を維持するための昔ながらの技術として「クッキー」があり、これもアクセストークンと見なすことができます。

これらは便利なものではありますが、もし仮にアクセストークンが漏洩した際、そのアクセストークンさえ持っていれば誰でもその Web サービスが使えてしまう、という問題があります。

このようなアクセストークンを『Bearer トークン』と呼びます。

この Bearer トークンのセキュリティリスクを緩和するために、TLS レイヤーとその上位レイヤーのアクセストークンを結び付けよう、というのが「トークンバインディング」の発想です。

RFC8705 Section1 には以下のように記載されています。

Binding an access token to the client's certificate prevents the use of stolen access tokens or replay of access tokens by unauthorized parties.

日本語訳。

アクセストークンをクライアント証明書とバインディングする (紐付ける) ことは、招かれざる客による盗難アクセストークンの不正利用やリプレイ攻撃を防ぎます。

実は他のプロトコルでも同じ目的で似たような仕組みを持つものもあります。

2020年3月頃に Windows Update により『デフォルト値が無効から有効に変わる』として話題になった AD ドメインコントローラの「LDAP チャネルバインディング」です。

これは「LDAPs で使う TLS コネクション」と「Kerberos や NTLM で生成されるチケットやアクセストークン」を結び付けるものでした。

LDAP署名/LDAPチャネルバインディングとCBT (Channel Binding Token) の仕組み
LDAP署名とLDAPチャネルバインディングの既定有効化 2020 年 3 月の...

RFC8471 - 8473 のトークンバインディングのシーケンス

他の事例として、RFC8471 - 8473 で規定されている、(OAuth2 ではない) 一般の https でのアクセスを想定したトークンバインディングがあります。

OAuth2 の Mutual-TLS Certificate-Bound-Access-Tokens では「TLS クライアント証明書」と「アクセストークン」を紐付けましたが、このトークンバインディングでは「TLS コネクション (EKM)」と「アクセストークン」を紐付けます。

OAuth2 Mutual-TLS Certificate-
Bound Access Tokens
Token Binding over HTTP
RFCRFC8705RFC8471
RFC8472
RFC8473
対象プロトコルOAuth2 over http + Mutual-TLShttp + TLS
アクセストークン
と紐づける対象
TLSクライアント証明書TLSコネクション (EKM)

EKM とは Exported Key Material と呼ばれる「クライアントとサーバで明示的に伝えずとも共通認識される乱数」のことで、TLS コネクションのたびに変化するものです。(RFC5705 で定義)

つまり、RFC8705 は『mutual-TLS であればクライアント証明書 (およびそれに紐付く秘密鍵/公開鍵) があるので、これによりクライアント証明書とアクセストークンを結び付ける』というアプローチでしたが、RFC8471-8473 は『一般的な https の場合はクライアント証明書を持たないため、その代わりにクライアント側が自前でデジタル署名用の秘密鍵/公開鍵のペアを生成し、これにより TLS コネクションとアクセストークンを結び付ける』というアプローチです。

以下に具体的なフローの概要を示します。

  • TLS の Client Hello と Server Hello にて新たな TLS extension (TLS 拡張属性) である "token_binding" でトークンバインディングプロトコルのネゴシエーションする (署名アルゴリズムの決定など)
  • TLS コネクションの確立により EKM がクライアントとサーバ間での共通認識となる
  • クライアントは http ヘッダフィールド「Sec-Token-Binding」に TBMSG (Token Binding MeSsaGe : EKM へのデジタル署名や TokenBindingID 等の情報を base64url enconding でエンコードしたもの) を埋め込み、サーバへ http リクエストを行う
  • サーバは TBMSG の中にある TokenBindingID (クライアントが生成したデジタル署名用公開鍵) を「クライアントの識別子」兼「公開鍵」として登録する
  • サーバは必要に応じてアクセストークンをクライアントへ払い出すし、その際にアクセストークンを TokenBindingID と紐づける
  • 次回以降の TCP/TLSコネクション時も、クライアントは http リクエストの際は必ず「Sec-Token-Binding」ヘッダに TBMSG を含める
  • サーバは必ず TBMSG 内にある EKM のデジタル署名を、登録した TokenBindingID (クライアントのデジタル署名用公開鍵) で検証し、アクセストークンがある場合はその TokenBindingID と紐づいていることを確認する (もし違う場合はアクセストークンの不正利用と見なしアクセス拒否する)

なお、RFC8473 Section5 には OAuth2 や SAML 等の Federation 向けのバインディング方法も紹介されています。

コメント

タイトルとURLをコピーしました