ハイライト
Apple は、2020 年に Sign in with Apple の nonce、state、credentialState、およびサーバー通知の処理を明確にし、既存のパスワード アカウントを Apple ID ログインにアップグレードしてアカウントの重複を回避できるようにするための Account Authentication Modification Extension を追加しました。
主要内容
Apple でサインインは、単なるサインイン ボタンのように見えます。製品に関して言えば、問題はボタンの背後にあります。ユーザーが初めて認証するとき、名前、電子メール アドレス、identityTokenそしてauthorizationCode;ネットワークに障害が発生すると、次回から名前とメールアドレスは表示されなくなります。ユーザーは、設定で認証を取り消したり、アプリケーションがプライベート電子メール リレー アドレスを受信できるように電子メール アドレスを非表示にすることを選択したりすることもできます。
このセッションでは、ログイン リンクをすぐに実行する必要があるいくつかの処理に分割します。リクエスト フェーズでは、一意のnonceそしてstate、コールバックフェーズの検証state、サーバーは解析して検証しますidentityToken、次に使用しますauthorizationCodeApple ID サーバーとの後続のセッションを確立します (02:02、05:37)。このようにして、クライアントが証明書を取得すると、それが自身のリクエストからのものであることがわかり、サーバーはトークンが再生または改ざんされていないことも確認できます。
ログインが完了しても、そのステータスが常に有効になるわけではありません。 Appleはアプリを起動またはフォアグラウンドに戻るときに呼び出すことを要求していますgetCredentialState、そしてのために.authorized、.revoked、.notFoundそして新しい.transferred別の処理を実行します (08:51、10:16)。アプリケーションがある開発チームから別の開発チームに移動された場合、.transferred開発者がユーザー ID をサイレントに移行できるようにします。
2020 年の新機能は 2 つの方向に焦点を当てています。まず、サーバーは Apple 署名の開発者通知を受信し、プライベートメールリレーが閉じられたかどうか、認証が取り消されたかどうか、Apple ID が削除されたかどうかを直接知ることができます (11:31)。 2 番目に、Account Authentication Modification Extension は、従来のユーザー名とパスワードのアカウントを Apple でサインインするようにアップグレードし、成功時に古い弱いパスワード資格情報をシステムに削除させることができます (16:50)。 29:42)。
詳細
1. 認可リクエストは nonce と state をもたらす必要があります
nonceそしてstateこれらはすべて、承認リクエストで送信される不透明な文字列です。nonce返されたものに埋め込まれますidentityToken、サーバーはそれを使用してリプレイ攻撃のリスクを軽減できます。state資格情報は直接返され、クライアントはこれを使用してコールバックとこのリクエストを組み合わせることができます。
// Configure request, setup delegates and perform authorization request
@objc func handleAuthorizationButtonPress() {
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
request.nonce = myNonceString()
request.state = myStateString()
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
キーポイント:
createRequest()Apple ID 認証リクエストを作成すると、すべてのセキュリティ パラメータがこのリクエストにハングされます。 -requestedScopesアプリケーションが本当に必要なものだけをリクエストするfullNameそしてemail。request.nonceリクエストごとに一意の値を生成し、その後サーバー側で使用する必要があります。identityToken検証。 -request.state返された資格情報がこのリクエストに対応していることをクライアントで確認するために使用されます。 -ASAuthorizationControllerシステム認証インターフェイスを表示し、デリゲートを通じて結果を返す責任を負います。
2. 必要な情報をコールバックに保存し、検証のためにサーバーに渡します。
Apple は、ユーザーが初めて認証する場合にのみ、名前と電子メール アドレスが認証情報に表示されることを明確に注意しています。アプリケーションは、ネットワークが良好でない場合に最初の認証情報が失われないように、必要なオブジェクトをローカルにキャッシュする必要があります。それから置きますidentityTokenそしてauthorizationCodeサーバーに送信され、サーバーは公開キー、有効期限、nonce、認証コードを使用して、Apple ID サーバーへの後続の呼び出しに必要なトークンを交換します。
// ASAuthorizationControllerDelegate
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userIdentifier = credential.user
let fullName = credential.fullName
let email = credential.email
let realUserStatus = credential.realUserStatus
let state = credential.state
let identityToken = credential.identityToken
let authorizationCode = credential.authorizationCode
// Securely store the userIdentifier locally
self.saveUserIdentifier(userIdentifier)
// Create a session with your server and verify the information
self.createSession(identityToken: identityToken, authorizationCode: authorizationCode)
}
}
キーポイント:
credential.userこれはアプリケーションが後でユーザーを識別するために使用するローカル ID であり、安全に保管する必要があります。 -fullNameそしてemailこれは最初の認証に対してのみ提供され、サーバー通信が失敗した場合でも復元できる必要があります。 -realUserStatus初めて許可されたときに返されます。値には、サポートされていない、不明、および実際に存在する可能性が高い値が含まれます。 -stateこれは、リクエスト中に生成された値と一致している必要があります。一致が失敗した場合は、ログイン プロセスを停止する必要があります。 -identityTokenこれは JSON Web トークン (JWT) です。サーバーは Apple 公開キーを使用して署名を検証し、有効期限を確認する必要があります。 -authorizationCodeサーバーに送信された後、リフレッシュ トークン、アクセス トークン、および新しいトークンを Apple ID サーバーと交換できます。identityToken。
3. アプリケーションが起動してフォアグラウンドに戻ったら、credentialState を確認します。
getCredentialState保存されたユーザー識別子を使用して資格情報のステータスを照会します。 Apple は、ユーザーがシステム設定から認証を取り消した後、アプリが即座にセッションを閉じることができるように、アプリの起動時またはフォアグラウンドに入ったときにこれを呼び出すことをお勧めします。
// Getting a credential state
let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: getStoredUserIdentifier()) {
(credentialState, error) in
switch(credentialState) {
case .authorized:
// Sign in with Apple credential Valid
case .revoked:
// Sign in with Apple credential Revoked, Sign out
case .notFound:
// Credential was not found, fallback to login screen
case .transferred:
// Application was recently transferred, refresh User Identifier
@unknown default:
break
}
}
キーポイント:
.authorized資格情報がまだ有効であり、ログイン インターフェイスをスキップしてアプリケーションに入ることができることを示します。 -.revokedユーザーが認証を取り消したため、アプリケーションがログアウトし、セッションを閉じて、ログイン ページを表示する必要があることを示します。 -.notFound対応する資格情報が見つからないため、アプリケーションがログイン ページに戻る必要があることを示します。 -.transferred2020 年の新機能は、アプリをある開発チームから別の開発チームに移動した後のユーザー ID の移行に適用されます。 -@unknown default新しいシステムが不明な列挙を返した場合のクラッシュを避けるために、将来の状態のために予約されています。
4. 既存のユーザー ID を使用して、チームの移行後に移行をトリガーします
Apple でサインインするユーザー ID は開発チームによって分離されます。会社の買収またはアプリケーションの譲渡後、古いチームのユーザー ID を新しいチームに移行する必要があります。対処する.transferred開発者が現在保存されているユーザー識別子を新しく要求されたユーザー識別子に入力するときrequest.user、システムは新しいチームに一致する ID を生成します。
// Migrating a user identifier
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
request.user = getStoredUserIdentifier()
request.nonce = myNonceString()
request.state = myStateString()
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
キーポイント:
- 移行プロセスでは、アカウントの作成またはユーザーのログインに認証リクエストが再利用されます。
-
request.user現在保存されているユーザー ID を入力して、これが移行リクエストであることをシステムに伝えます。 -nonceそしてstate引き続き設定を行う必要があり、移行プロセスでは同じリクエスト検証を維持する必要があります。 - コールバックはまだ通過します
ASAuthorizationControllerデリゲートが返され、アプリケーションはユーザーが意識することなくローカル ID を更新できます。
5. サーバー通知を使用して承認とメールボックスのステータスの変更を処理する
クライアントのライフサイクル チェックは、デバイスの状態のみをオーバーライドできます。 2020 年に、Apple はサーバー間の開発者通知を追加しました。開発者が Apple Developer Web サイトにエンドポイントを登録すると、Apple はイベントを自己署名 JWT としてサーバーに送信します。
register server endpoint on Apple Developer website
events are JSON Web Tokens signed by Apple
email-disabled
email-enabled
consent-revoked
account-delete
キーポイント:
email-disabledユーザーがプライベート電子メール リレーによって転送された電子メールの受信を停止することを示します。 -email-enabledユーザーがプライベート電子メール リレーを再度開いて電子メールを受信することを示します。 -consent-revokedユーザーがアプリケーションでの Apple ID の使用を停止し、ユーザーのログアウトとして扱う必要があることを示します。 -account-deleteユーザーが Apple に Apple ID の削除を要求し、関連するユーザー ID が有効でなくなったことを示します。- これらの通知はサーバーに直接送信され、アカウントのステータス、電子メール送信戦略、リスク管理記録の更新に適しています。
6. SwiftUI で SignInWithAppleButton を使用して、同じリクエスト パラメーターのセットを受け入れます
SwiftUIの新機能SignInWithAppleButton。ボタン自体を選択することもできますSignIn、ContinueまたはSignUpラベル、onRequestスコープを設定するnonceそしてstate,onCompletionここで認証の成功または失敗を処理します。ボタンのスタイルは、黒、白、白のアウトラインをサポートしています。
// SwiftUI example:
SignInWithAppleButton(.signIn) {
onRequest: { (request) in
request.requestedScopes = [.fullName, .email]
request.nonce = myNonceString()
request.state = myStateString()
}
onCompletion: { (result) in
switch result {
case .success(let authorization):
// Handle Authorization
case .failure(let error)
// Handle Failure
}
}
}.signInWithAppleButtonStyle(.black)
キーポイント:
SignInWithAppleButton(.signIn)システム スタイルの Apple ログイン ボタンを作成します。 -onRequest認可リクエストを設定する場所です。 UIKit プロセスと同じ方法で設定する必要があります。nonceそしてstate。onCompletion認証結果を処理し、成功した場合は解析を続行します。authorization。.signInWithAppleButtonStyle(.black)ボタンのスタイルを選択します。セッションでは白と白のアウトラインについても言及されています。
7. アカウント変更拡張機能を使用して既存のパスワード アカウントをアップグレードする
「Apple でサインイン」へのアップグレードは、ユーザー名とパスワードがすでにあるアカウントを対象としています。システムは、アカウント認証変更拡張機能を介してアプリケーション拡張機能を呼び出します。まず、インターフェイスなしで既存のインターフェイスを検証してみます。ASPasswordCredential。検証が成功すると、拡張機能は Apple ID 認証情報を要求し、サーバーはアカウントの変換を完了し、拡張機能は完了メソッドを再度呼び出します。システムは古いパスワード認証情報を削除します。
enum VerificationResult : Int { case success; case failure; case twoFactorAuthRequired;
override func convertAccountToSignInWithAppleWithoutUserInteraction(
for serviceIdentifier: ASCredentialServiceIdentifier,
existingCredential: ASPasswordCredential
) {
verifyCredential(existingCredential) { (result: VerificationResult) in
switch result {
case .failure:
self.extensionContext.cancelRequest(withError:
ASExtensionError(.failed))
case .success:
self.extensionContext.getSignInWithAppleAuthorizationWithState(state: myStateString(),
nonce: myNonceString(),
{…}
case .twoFactorAuthRequired:
self.extensionContext.cancelRequest(withError:
ASExtensionError(.userInteractionRequired))
}
}
キーポイント:
convertAccountToSignInWithAppleWithoutUserInteractionこれはインターフェースレス アップグレードの最初のステップであり、目的はユーザーの余分な操作を減らすことです。 -existingCredentialこれはシステムによって渡された既存のパスワード認証情報であり、拡張機能は最初にそれがまだ有効であるかどうかを確認する必要があります。 -.failure歩くASExtensionError(.failed)、アップグレードプロセスを終了します。 -.success電話getSignInWithAppleAuthorizationWithState、バンドルstateそしてnonceApple ID 認証プロセスに渡します。 -.twoFactorAuthRequired歩くASExtensionError(.userInteractionRequired)これにより、システムはステップアップ セキュリティ (補足検証) インターフェイスを表示します。- サーバーがアカウントの変換を完了すると、拡張機能は完了メソッドを呼び出し、システムは古い弱いパスワード資格情報を削除して、ユーザーが次回ログインするときに 2 つのアカウント エントリが表示されないようにします。
重要ポイント
-
ログイン コールバックを再開可能なプロセスにします
- 内容: 最初の認証時にすぐにキャッシュします
userIdentifier、名前、メールアドレス、state、identityTokenそしてauthorizationCode処理状況。 - 実行する価値がある理由: セッションでは、名前と電子メール アドレスが最初の認証時にのみ返されることが明確に述べられています。ネットワーク障害により、アカウント作成プロセスでデータが失われます。
- 開始方法:
authorizationController(controller:didCompleteWithAuthorization:)まずローカルの回復ポイントを保存し、次にサーバーを呼び出してセッションを作成します。
- 内容: 最初の認証時にすぐにキャッシュします
-
非表示のメールボックスに独立ステータスを追加
- 対処方法: ユーザー プロファイルまたはメール システムでプライベート電子メール リレー アドレスをマークし、記録します。
email-disabledそしてemail-enabled通知します。 - 価値がある理由: Apple は、リレー アドレスはチームごとに分離され、Apple によって検証され、ユーザーがメール転送をオフまたはオンにできると説明しています。
- 開始方法: サーバー通知エンドポイントを登録し、
email-disabledマーケティングメールを一時停止するトリガー、email-enabled送信可能な状態を復元するためにトリガーされます。
- 対処方法: ユーザー プロファイルまたはメール システムでプライベート電子メール リレー アドレスをマークし、記録します。
-
認証の取り消しと同時のログアウト
- 内容: クライアントのリスニング
.revoked、サーバー側の処理consent-revoked、どちらのパスも同じアカウント終了プロセスに入ります。 - 実行する価値がある理由: ユーザーはシステム設定からアプリを切断できます。クライアントの次回の起動のみに依存すると、サーバー側のステータスに遅れが生じます。
- 起動方法: アプリケーションの起動とフォアグラウンドへのコールバック
getCredentialState、サーバーは受信しますconsent-revoked次に、セッションを閉じて、リフレッシュ トークンをクリアします。
- 内容: クライアントのリスニング
-
弱いパスワードを持つユーザーにワンクリック アップグレード エントリを提供
- 対処方法: アカウント セキュリティ ページに「Apple でサインインするためのアップグレード」を追加し、パスワード マネージャーからシステムによって開始されるアップグレードをサポートします。
- 実行する価値がある理由: Account Authentication Modification Extension は、既存の資格情報を使用してアカウントを確認できます。成功すると、システムは古い弱いパスワード認証情報を削除します。
- 開始方法: 実装
ASAccountAuthenticationModificationViewControllerサブクラスでは、インターフェイスレス検証を優先します。二次検証が必要な場合にのみ返されますuserInteractionRequired。
関連セッション
- ワンタップ アカウント セキュリティ アップグレード - アカウント認証変更拡張機能、強力なパスワードのアップグレード、および Apple でサインインのアップグレード プロセスについての詳細な説明。
- ウェブ用の Face ID と Touch ID の紹介 — Web 認証 API に基づいた、Safari での Web サイト ログインの代替手段を紹介します。
- アプリの保護: 脅威モデリングとアンチパターン — ログイン、トークン、状態管理の背後にある脅威モデリングのアイデアを完成させるのに適しています。
コメント
GitHub Issues · utterances