iOS/Androidアプリの2要素認証対応 - TOTP認証アプリ設定編

## はじめに

Webサービスの個人認証において、[Google認証システム (Google Authenticator)](https://support.google.com/accounts/answer/1066447) のようなTOTP認証アプリによる2要素認証を利用することでセキュリティを向上させることができます。しかしながら、その設定方法やその後の運用は非常に難解で、正しく設定できずに挫折してしまったり、スマートフォンの機種変更などにより２度とログインできなくなってしまったというケースも良く耳にしますよね。

そのため、自身で開発しているiOS/AndroidアプリでTOTP認証アプリでの2要素認証に対応する場合、できるだけユーザーに優しいUIで作りたいです。この記事では、iOS/AndroidのOSの仕組みを最大限に活用してTOTP認証アプリ対応するために検討した内容を複数回にわたって共有しようと思います。まずは最も難解な、TOTP認証アプリ設定についてです。

以後、TOTP認証アプリのことを「認証アプリ」と表記します。また、この記事ではTOTP認証アプリの仕組みについては触れませんので、以下の記事などをご覧ください。

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

## 認証アプリの設定手順

認証アプリの設定は以下のような手順となります。下図は [マイニンテンドー](https://my.nintendo.com/) の2要素認証設定画面ですが、どのWebサービスやアプリにおいても同じ様な手順です。

1. 認証アプリをインストールする
2. 認証アプリにシークレットキーを登録する
3. 認証アプリに表示された確認コードを入力する

<img width="240" alt="2要素認証設定(マイニンテンドー)" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/22366834-70ae-cafe-6693-de0828bcd848.png">

この手順で最も難しいのが2番目の、認証アプリにシークレットキーを登録する部分です。登録方法は主に以下の3種類です。

- QRコードを読み取る
- 手入力する
- otpauth URIリンクから

### QRコードを読み取る
シークレットキーなどの情報が含まれるQRコードを、認証アプリからカメラで読み込む方法です。これは一見簡単そうに見えるのですが、iOS/Androidアプリに表示されたQRコードを、同じスマートフォンの認証アプリから読み取るということはできないという罠にひっかかります。

QRコードが有効に利用できるのは、PCのウェブブラウザなどで表示されたQRコードをスマートフォンで読み取るケースのみです。

認証アプリによっては、QRコードの表示された画面をスクリーンショットで撮影し、それを入力して登録できるものもあるかもしれません。しかしこの作業も一般的な人にとっては難しい作業になると思います。

### 手入力する
シークレットキーはランダムな英数字で構成されているため、それをクリップボードにコピーするなどして認証アプリに手入力することができます。

### otpauth URIリンクから
先ほどのQRコードの中身は `otpauth` スキームの以下のようなURIです。

```
otpauth://totp/example:example.com?secret=secretkey&issuer=example.com&digits=6&period=30
```

https://lab.tricorn.co.jp/uzuki/5129

ということはこのスキームに認証アプリ側が対応していれば、このURIリンクをタップするだけで設定が完了する可能性があります。つまり、これを確認できればスマートフォンで最も簡単な認証アプリ設定方法になるのです。

さきほどのマイニンテンドーの例でも、手入力用のシークレットキーのテキストが、このURIのリンクになっていました。

## otpauthスキーム対応状況の調査
ということで、iOS/Androidそれぞれにおいて、otpauthスキームのURLから認証アプリの設定ができるかを確認します。今回試した認証アプリは以下の4つです。

- [Google Authenticator](https://support.google.com/accounts/answer/1066447)
- [Microsoft Authenticator](https://www.microsoft.com/ja-jp/security/mobile-authenticator-app)
- [Twillio Authy](https://authy.com)
- [IIJ SmartKey](https://www.iij.ad.jp/smartkey/)

### Android
Androidに認証アプリをインストールし、テスト用に用意した otpauth スキームのリンクをタップします。

その結果、下図のように IIJ SmartKey 以外のアプリが候補として現れました。そのまま各アプリで開いてみましたが、すべてシークレットキーの登録まで完了しました :tada:

<img width="300" alt="Androidでotpauthスキームに反応したアプリ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/44acb4dd-7e36-ba02-3cdd-a5b1b1ea55b4.png">

上記画像は先日リリースされたばかりの Android 12 での確認結果ですが、Android 6でも動作しました。

### iOS
iOSにも4つの認証アプリをインストールして試してみました。その結果、以下のように Google Authenticator で開くか確認するダイアログが表示され、開くと設定まで完了しました。

<img width="300" alt="iOSでotpauthスキームに反応したアプリ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/d5567349-2fe0-0a6e-48f0-4fbafb402125.png">

iOSのURLスキームの仕組みでは、上記のようにインストールされている任意の１つのアプリを開こうとします。そのため複数の対応アプリがある場合に意図したアプリが開けないため困ってしまいますね。

各アプリの対応状況を調べるため、1つずつ認証アプリを削除しながら試したところ、Androidと同様で IIJ SmartKey 以外のアプリはリンクからの設定ができました。

### 🆕iOS15

先ほどは iOS12-14で確認しましたが、リリースされたばかりの iOS15 はどうでしょうか。iOS15 では標準搭載されている Keychain が認証アプリとして機能するようになりました。詳細は WWDC2021 の以下のセッションビデオをご覧ください。

https://developer.apple.com/videos/play/wwdc2021/10105/

これにより、iOS15で otpauth スキームのリンクから Keychain が表示され、Keychain に登録されたアカウント情報にシークレットキーを紐づけるような動きになりました。OSが標準でパスワードマネージャーや認証アプリとしての機能を持つことはとても素晴らしいことですね！

しかし、iOS15では必ず Keychain が開いてしまいます‼️しかも Keychain は iOS に組み込まれているので削除することはできません。この動きを変更するような設定も見つかりませんでした・・・。

私は普段、3rd Partyのパスワードマネージャーを使っていますし、認証アプリもそれに搭載された機能で賄っているので、ガッカリしすぎてついこんな呟きを。

https://twitter.com/temoki/status/1451079086550355970

Apple さん、今後のバージョンアップで良いので他の認証アプリへの配慮もお願いしたいものです。

### 調査結果より

以上の調査結果より、otpauth URIリンクによる設定は最も簡単な設定方法であることは間違いありませんが、以下の問題があることがわかりました。

- otpauthスキームに対応していない認証アプリでは動作しない
- iOS15未満では、複数の認証アプリがインストールされている場合に、意図したアプリで動作しない場合がある
- iOS15では、必ず Keychain で設定しようとしてしまう

## まとめ

iOS/Androidアプリで2要素認証に対応するにあたり、OSや状況に応じて認証アプリの各設定方法が有効かどうかを表にまとめます。

- ◎ : 簡単に設定できる
- ◯ : 設定できる
- △ : 設定できない場合がある
- × : 設定できない

| OS | その他の条件 | QRコードを<br>読み取る | 手入力する | otpauth<br>URIリンクから |
| --- | --- | :-: | :-: | :-: |
| Android | otpauthスキーム対応の認証アプリ/あり | × | ◯ | ◎ |
| Android | otpauthスキーム対応の認証アプリ/なし | × | ◯ | × |
| iOS 15未満 | otpauthスキーム対応の認証アプリ/あり(１つ) | × | ◯ | ◎ |
| iOS 15未満 | otpauthスキーム対応の認証アプリ/あり(複数) | × | ◯ | △ |
| iOS 15未満 | otpauthスキーム対応の認証アプリ/なし | × | ◯ | × |
| iOS 15 | - | × | ◯ | × |
| iOS 15 | Keychainユーザー | × | ◯ | ◎ |

以上から、iOS/Androidアプリで2要素認証の認証アプリ設定画面を作る場合、以下のことを意識しておくと良いではないかと思いました。

- シークレットキーを手入力する方法は必ず用意する
- otpauth URLリンクは状況によっては最も簡単なので、オプション的な位置付けで用意しておくとよさそう
- ~~QRコードでは設定できないが、2要素認証のシンボルとして認識されていそうなので、表示はしておくとよさそう~~ 👉 何人かにユーザーレビューをしたところ、2要素認証のシンボルとしての効果は薄く、逆に混乱を招いたので、モバイルアプリからの利用時には表示しない方が良さそう

こう考えると最初に例に挙げたマイニンテンドーはこれらが考慮されたものになっていますね。マイニンテンドーは2要素認証のヘルプも動画解説があったりしてとてもユーザーに優しく、流石だなあと思いました。

あとはiOS15が3rd Partyの認証アプリにも対応し、かつ認証アプリはすべてotpauthスキームに対応されるとユーザーにとって優しい世界に近づきますね！