業務でFace ID, Touch IDを使ったログイン機能を実装することになったので色々と調べた。
作成予定のシステム
- Ionic(JavaScript, Angular)で作成されたハイブリットモバイルアプリケーション
- サーバーサイドはJava(Spring)
- 通常のログインには、メールアドレスとパスワードを使用
- Face ID, Touch IDによる認証が成功した時には、メールアドレス/パスワード の入力をスキップした状態でログインできる
Face ID, Touch IDに対する誤解について
Face ID, Touch IDによる認証が成功すると、認証した人を特定できるユニークなIDを発行してくれるイメージを勝手に持っていたが、そんな機能はなかった。Face ID, Touch ID のAPIが提供する情報は、あくまで認証が「成功したかどうか」のみでIDを発行したりはしない。
処理詳細
過去に類似の実装経験がある人に話を聞いた結果、下記のイメージで実装する予定。
初回ログイン
- UDIDを発行して、iOSデバイスのキーチェーンに格納
- ユーザーがログイン画面にメールアドレスとパスワードを入力してログイン
- この時、発行したUDIDもサーバーに送る
- 「UDID」と「メールアドレス・パスワード」を関連付けてDBに保存
- これで次回以降は、Face ID, Touch IDによる認証が有効になる
Face ID, Touch IDによるログイン
- Face ID or Touch IDを実行して成功する
- iOSデバイスのキーチェーンからUDIDを取り出す
- UDID+固定文字列をHMAC-SHA256形式でハッシュ化
- ハッシュと現在時刻を連結させたものを、AES256で暗号化、暗号化した結果をBASE64Encodeするこれをシグネチャとする
- シグネチャをサーバーに送る
- サーバー側でBASE64Decode、AES復号化、送られてきた現在時刻から10分以上経過していないことを確認する
- ハッシュが一致することを確認する
- UDIDが正しく登録されているか確認する
- 認証処置完了、認証トークンを発行する
Appleのレビューガイドライン
Appleのレビューガイドラインで、Face IDについての記載があったので転載する。
https://developer.apple.com/jp/app-store/review/guidelines/
2.5.13 顔認証でアカウントを認証するアプリケーションには、ARKitやその他の顔認証テクノロジーではなく、必ずLocalAuthenticationを使用する必要があります。また、13歳未満のユーザーに対しては、必ず代替の認証方法を用意する必要があります。
考えた点・補足
- 端末のKeychainに直接メールアドレスとパスワードを保管するのは避けた
- シグネチャは、改ざん防止ではなく、認証のために利用している
- 顔・指紋認証に3回失敗すると、通常ログインに切り替える〜みたいな処理は、API(ライブラリ)側で勝手にやってくれる
結局違う設計にしました。この記事参照