MFA設定時のQRコードが漏えいしたら

# はじめに
　Gmailなどのクラウドサービスでは，ワンタイムパスワードなどのMFA（多要素認証）を設定できます。ワンタイムパスワードを利用するための手順として，QRコードをGoogleAuthenticatorなどのアプリにに読み込ませる手順が一般的です。この仕組みは[RFC](https://datatracker.ietf.org/doc/html/rfc6238)で標準化されており，多くのサービスで利用されています。
　この記事では，MFAを設定する際のQRコードが漏えいすることの危険性を検証してみました。

# この記事で使う言葉の定義
- TOTP:時間ベースのワンタイムパスワード。6桁や8桁の数字。
- TOTPアプリ：TOTPを表示させるスマホアプリ。本記事ではGoogleAuthenticatorを使います。
- サービス：ユーザが入力したID，パスワード，TOTPを受信し，認証を行います。本記事では，Googleアカウントサービスを使います。

# TOTPのしくみ
　TOTPの仕組は，本記事で解説しなくてもわかりやすい[記事](https://www.itmedia.co.jp/news/articles/1904/08/news026_3.html)が各所にありますのので，本記事では割愛します。

# 試してみた
- 手順1（正規手順）：Googleアカウントの2段階認証を有効化し，「認証システムアプリ」で認証アプリを追加をします。このとき，TOTPアプリに読み込ませるQRコードが表示されます。
- 手順2（正規手順）：スマホAにインストールしたGoogleAuthenticator（以下，「TOTPアプリ（スマホA）」）でQRコードを読取り，スマホAでTOTPを表示できるようにします。
- 手順3（イレギュラー手順）：表示されたQRコードを画面キャプチャします（このQRコードが，悪意のある第三者にわたってしまうと想定します。）
- 手順4（正規手順）：Googleアカウントで，TOTP設定を完了させます。このタイミングで，Googleアカウントログイン時にTOTPが有効になります。
-  手順5（イレギュラー手順）：その後ある程度の時間をおいてから（今回のテストでは9時間程度経過）スマホBにインストールしたGoogleAuthenticator（以下，「TOTPアプリ（スマホB）」）に，手順3でキャプチャしたQRコードを読取らせます。QRコードは認識され，TOTPアプリ（スマホB）でTOTPが表示されるようになります。
-  手順6：TOTPアプリ（スマホA）とTOTPアプリ（スマホB)では，常に同じTOPTが表示されることが確認できます。

このテストが何を意味するかというと，「ワンタイムパスワードアプリに読み込ませるQRコードが漏えいしてしまうと，QRコードを入手した人はワンタイムパスワードを生成できてしまう。」ということです。

# なぜこのようなことが起きるのか
- QRコードに，QRコード自体の有効期間を設定する仕組みがない
　QRコードには，otpauthリソースをURIスキームで表現した文字列が格納されています([参考](https://www1.auth.iij.jp/smartkey/uri_v2.html))。

```
otpauth://totp/[issuer]:[accountname]?secret=[secret]&issuer=[issuer]&algorithm=SHA1&digits=6&period=30
```
　パラメータで秘密鍵やTOTPの桁数，TOTPの有効期間などが指定できるのですが，QRコード（というかURI）自体の有効期間を設定するパラメータが存在しません。そのため，QRコード（＝URI）を入手してしまうと，いつでもこのQRコードをTOTPアプリに登録できてしまいます。
　仮にQRコードに有効期間が設定できたとしても，TOTPアプリ（が動作するスマホ）側の時刻をずらしてしまえば，有効期間内であると誤認させてTOTPアプリに登録できてしまいます。また，QRコードから抽出したURIから有効期間を削除あるいは改ざんしたURIを生成することも考えられます。この場合，パラメータの削除や改ざんを検知する仕組みがないので，さらに厳格にしようとすると署名をURIに含めるような仕組みが必要でしょう。そうすると，じゃあ署名を検証するための公開鍵をどのようにTOTPアプリが入手するのか，などどんどん深みにはまってしまいます。（TOTPの仕組み自体は，このあたりをある程度割り切った仕組みのようです）
- 複数のTOTPアプリに秘密鍵が登録されたことを，サービス側が知る手段がない
　QRコードでの通知は一方通行で，TOTPアプリからサービス側への通信は発生しません。そのため，同時あるいは時間差でQRコードが複数のTOTPアプリに登録されても，サービス側ではそれを知る手段がありません。そのため，「正規のタイミングで登録されたTOTPアプリが発行したTOTP」と「後から（不正に）登録されたTOTPアプリが発行したTOTP」を，サービス側では区別できません。

# rfc6238の解釈
　TOTPを規定した[rfc6238](https://datatracker.ietf.org/doc/html/rfc6238#section-8.1)の5.1Generalには次の記載があります。(一部のみ要約）
- 鍵は検証システム内に安全に保管することを推奨する、
- 全ての通信は，TLSやIPsecのような安全なチャネルを介して行われるべき

 RFCには直接書かれていませんが，鍵（共有秘密鍵）の安全性が担保できない場合には，TOTPの安全性は担保できないと解釈できます。そもそも共通鍵方式なので，鍵の漏えいに対して脆弱なのは，当然と言えば当然のことです。

# まとめ
　QRコードが漏えいすると，有効なTOTPを第三者が生成でき，不正ログインを許してしまいます。
　TOTPの安全性は結局のところ，共有秘密鍵であるQRコードの受け渡しをどこまで安全に行うかに大きく影響を受ける，ということでした。

# さいごに
　この記事にはTOTPを否定する意図はまったくありません。共通鍵からTOTPを生成する仕組みなので，共通鍵（共有秘密鍵）の漏えいに弱いのは，理論上しかたがないかなと思います。危険性を認識し，QRコードの漏えいに気をつけましょう。
　ちなみにこの仕組みを使うと複数のスマホに同じTOTPを表示させることができます。予備スマホに同時にQRコード読み込ませておけばをスマホの故障や電池切れの際に予備スマホでTOTPを取得できます。

 
# ＜参考URL＞TOTPに関する情報
https://www.itmedia.co.jp/news/articles/1904/08/news026_3.html

https://blog.apar.jp/program/13225/#toc8

https://github.com/google/google-authenticator/wiki/Key-Uri-Format

https://sekika.github.io/2016/03/26/GoogleAuthenticator/


# ＜参考URL＞QRコードあるいは秘密鍵の漏えいに関して言及されているサイト


[「QR コードを画面に表示したまま席を立つなどして他者に読み取られる」](https://blog.manabusakai.com/2014/10/two-factor-auth/)
[「最初に行われる秘密鍵の送受信は完全にプライバシーを守って行われなければならない」](https://gigazine.net/news/20190715-getting-2fa-right/)
[「共有秘密鍵を盗む攻撃者は、新しい有効なTOTP値を自由に生成できる。」](https://www.wikiwand.com/ja/%E5%88%A9%E7%94%A8%E8%80%85:Miya/%E6%99%82%E9%96%93%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%AF%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0#%E5%BC%B1%E7%82%B9%E3%81%A8%E8%84%86%E5%BC%B1%E6%80%A7)
[「TOTPは中間者攻撃に弱い」](https://www.gitlab.jp/blog/2022/10/24/2fa/)