WWDC Quick Look 💓 By SwiftGGTeam
One-tap account security upgrades

One-tap account security upgrades

观看原视频

Highlight

iOS 14 的 Account Authentication Modification Extension 让系统密码管理器和应用内设置页把有风险的密码账号一键升级为强密码或 Sign in with Apple,并在成功后更新或移除 iCloud Keychain 中的旧凭据。

核心内容

很多账号风险会在密码长期复用后浮出水面。登录当下很顺利,也挡不住同一串密码在其他服务泄露。iCloud Keychain 已经能保存密码、提供 Password AutoFill,也能帮用户减少输入负担。到了 iOS 14,系统密码管理器开始把风险直接摆到用户面前:重复使用、容易猜到、出现在公开数据泄露中的密码都会进入 Security Recommendations。

旧流程的问题很现实。系统可以把用户带到网站的 change password URL,但用户仍然要打开网页、找到表单、输入旧密码、设置新密码。Jay Mulani 在演讲里直接指出,大多数用户会避开改密码,因为这件事感觉很麻烦。

Apple 的改动是把“修复账号”变成系统级升级动作。Account Authentication Modification Extension 可以出现在密码详情页、高优先级安全建议,以及用户用弱密码或泄露密码登录应用后的系统提示里。一次扩展实现可以支持两条路:改成 iCloud Keychain 生成的强密码,或者把账号升级到 Sign in with Apple。

同一套能力也能放进应用自己的账号设置页。应用创建升级请求,扩展完成后由系统更新或移除 keychain 凭据。用户看到的是一个短流程;开发者要负责的是扩展授权、服务端提交账号变更、必要时展示额外验证界面。

详细内容

关联 app 和服务域名

06:15)扩展要能升级 iCloud Keychain 里的账号,app 必须先和服务域名建立安全关联。流程和 Password AutoFill 一样:服务端提供一个 JSON 文件,声明域名和 app 的关系;Xcode 里给 app 添加 Associated Domains capability,并写入匹配的域名。

关键点:

  • JSON 文件使用 web credential service,把域名和 app 绑定到认证场景。
  • Associated Domains entitlement 是系统判断这个 app 是否能为某个域名凭据提供升级的依据。
  • 完成关联后,保存在用户 iCloud Keychain 中、属于该服务的密码才有机会出现升级入口。
  • 这个前置步骤同时影响系统密码管理器里的升级按钮和应用内触发的升级流程。

支持强密码升级

07:17)强密码升级从一个新的 Account Authentication Modification Extension target 开始。扩展模板默认声明支持两类升级;如果只想支持强密码,需要在扩展的 Info.plist 中保留 strong password change 支持项。

08:23)当用户从密码管理器或登录后的系统提示触发强密码升级时,系统会启动扩展,把已有凭据、服务标识符、系统生成的新强密码传给扩展。系统发起的请求里,userInfo 始终为空。

关键点:

  • 扩展中的 view controller subclass 是业务逻辑入口,可以和后端通信,也可以在必要时展示验证界面。
  • 扩展收到请求后先向后端确认这次升级是否被授权,也可以读取 app 和扩展共享容器里的登录 cookie 或 token。
  • 授权失败时,扩展用 failure error code 取消请求;需要向用户解释原因时,可以通过 localized failure reason error key 提供文案。
  • 授权成功后,后端提交密码变更,扩展再用更新后的 username 和 password 完成 change password request。
  • 如果系统生成的强密码不符合服务端规则,可以用 password rules 约束生成规则,并把要求写入扩展 Info.plist 的 password generation requirements key。

支持升级到 Sign in with Apple

11:39)升级到 Sign in with Apple 的前提,是 app 已经支持 Sign in with Apple。扩展同样需要在 Info.plist 中声明支持 upgrade to Sign in with Apple。系统触发时,扩展会收到已有密码凭据、服务标识符,以及为空的 userInfo

13:36)授权通过后,扩展要向系统请求 Sign in with Apple credential。请求时可以带上 statenonce,用于后端验证 Apple ID 凭据。扩展完成服务端提交后,调用完成升级的方法;升级完成后,系统会删除用于升级的 keychain 密码凭据。

关键点:

  • 后端仍然是升级是否允许发生的判断点,不能只依赖客户端状态。
  • 系统可能因为用户取消 Sign in with Apple 面板或网络问题拿不到 credential,扩展要按失败路径取消请求。
  • 服务端完成账号绑定后,扩展再通知系统升级完成。
  • 成功升级到 Sign in with Apple 后,不应该继续允许这个账号用密码登录。

需要额外验证时展示 step-up UI

15:08)理想路径里,扩展可以不展示界面就完成升级。但如果服务需要二次验证,比如短信二步验证,扩展可以先用 user interaction required error code 取消初始请求。系统随后会创建允许交互的新请求,并调用准备界面的方法。

关键点:

  • 强密码升级进入 prepare interface to change password。
  • Sign in with Apple 升级进入 prepare interface to convert account to Sign in with Apple。
  • 系统会给扩展界面加上导航栏、app 名称标题和取消按钮。
  • 用户取消时,系统调用 cancel request;如果开发者重写该方法,最后仍然要尽快取消请求。
  • 额外验证完成后,流程回到前面的强密码提交或 Sign in with Apple credential 请求。

在应用内主动发起升级

18:06)实现扩展后,app 可以在账号设置页主动发起升级。应用创建升级请求并执行它,系统启动同一个扩展。应用内请求只带 username,不带 password,因为 app 不应该提供明文密码,也没有系统持有的 keychain credential handle。

19:19)强密码应用内升级需要服务标识符、用户名,以及可选的 userInfo 授权信息。演讲中的 Shiny app 把当前登录用户的 auth token 放进 userInfo,让扩展用它向后端确认升级权限。请求执行时,app 还要提供 controller delegate 和 presentation context provider。

20:22)应用内 Sign in with Apple 升级只是在请求对象上不同,结果回调方式相同。成功时,delegate 方法负责通知用户;系统随后查找同一服务和用户名的 keychain 凭据,并按升级类型更新或删除它。失败时,delegate 方法负责显示失败原因。

关键点:

  • userInfo 是应用内升级和系统发起升级的主要差异,系统发起时它为空,应用内发起时可传授权上下文。
  • presentation context provider 告诉系统在哪个窗口展示必要 UI。
  • delegate 成功回调适合更新账号设置页状态,比如隐藏“升级到 Sign in with Apple”按钮。
  • delegate 失败回调要把后端授权失败、网络失败、用户取消等情况映射成用户能理解的提示。

核心启发

  • 账号安全页的一键升级 做什么:在账号设置页增加“升级到 Sign in with Apple”和“改用强密码”两个入口。 为什么值得做:演讲明确说明应用内升级可以复用系统集成的账号安全升级流程,成功后系统会更新或移除 keychain 凭据。 怎么开始:先实现 Account Authentication Modification Extension,再用服务标识符、username 和 userInfo 中的登录 token 创建应用内升级请求。

  • 泄露密码的快速修复路径 做什么:当用户因弱密码或泄露密码登录后,提供不离开 app 的修复动作。 为什么值得做:iOS 14 会在用户使用有风险密码登录 app 时出现系统提示,扩展能把这个提示接到真正的账号变更流程。 怎么开始:让扩展支持 strong password change,在后端添加提交新密码的升级接口,并检查默认强密码是否符合现有密码规则。

  • 需要二次验证的安全升级 做什么:对高风险账号,在升级前要求短信验证码或已有二步验证。 为什么值得做:扩展支持 security step-up UI,可以在保留系统升级入口的同时完成服务自己的授权要求。 怎么开始:后端返回“需要进一步授权”时,让扩展用 user interaction required error code 触发交互式请求,再在扩展界面里完成验证。

  • App Clip 到完整 app 的账号接续 做什么:用户从 App Clip 进入完整 app 后,引导其把临时或密码账号升级成更安全的登录方式。 为什么值得做:演讲把 App Clip 到完整 app 的过渡列为适合提供账号安全升级的机会。 怎么开始:完整 app 登录后,在账号设置或 onboarding 末尾发起应用内升级请求,并把当前登录状态放入 userInfo 供扩展授权。

  • 共享容器里的扩展授权 做什么:让 app 和扩展共享登录 cookie 或 token,减少升级时的重复登录。 为什么值得做:演讲建议扩展可复用保存在共享数据容器中的登录状态,从而让升级尽量快速、少打断。 怎么开始:把扩展加入同一个 app group,只存放升级授权需要的短期状态,并让扩展在收到系统请求后先读取共享容器再访问后端。

关联 Session

评论

GitHub Issues · utterances