代理批准的 Touch ID 回退路径安全吗?
介绍代理批准中的 Touch ID 回退路径,涵盖合盖模式、外接键盘、扫描失败、传感器锁定、等待和强制停止。

Touch ID 批准流程会以各种普通方式失败:笔记本电脑合上了盖子,外接键盘不符合要求,传感器没有识别手指,或者 macOS 在多次失败后锁定了生物识别。如果代理能把这些情况变成含糊不清的批准状态,系统就已经犯下了危险的错误。回退路径必须明确说明操作仍在等待、已经确定被拒绝,还是在等待一次独立的认证事件。
这听起来像界面问题,直到代理手里拿着 SSH 权限,或正在准备经过认证的 API 请求。此时每一个含糊状态都会变成实际的运行行为。除非网关返回精确结果,否则代理无法理解“稍后重试”。当屏幕上只有一个迟迟不消失的生物识别提示,而请求是否仍然有效也不清楚时,人类同样很难做出正确判断。
我采用的设计原则很简单:生物识别失败可以延迟请求,但绝不能扩大权限。传感器不可用可以让流程转交人工决定,但绝不能让代理自行选择更弱的路径。锁定的凭据保险库会暂停所有依赖密钥的工作,直到规定的门槛再次打开。
Touch ID 可用不等于操作已获批准
Touch ID 回答的是:macOS 此刻能否通过生物识别传感器验证某个人。批准回答的是:这个经过验证的人是否授权了当前代理进程或拟执行的操作。把两者当成同一个事件,会产生糟糕的回退行为,因为失败原因属于不同层次。
按会话批准可以是一个简单的人工决定:用户查看发起请求的进程身份,然后接受或拒绝这次运行。按调用批准则会再次询问,因为凭据所有者认为某个密钥足够敏感,需要逐次确认。这两种决定都不能说明加密凭据保险库当前可用。保险库可能仍处于锁定状态,Mac 可能停留在登录窗口,物理传感器也可能无法访问。
Sallyport 让这种分离真正发挥作用,而不是停留在概念上。它的保险库门是绝对的:保险库锁定期间,所有操作都会被拒绝。只有保险库门允许操作后,按会话授权和按调用密钥才会决定代理权限。这样,界面友好的批准卡片就无法绕过锁定的保险库,变成后门。
这种区分也能避免一个常见但粗糙的建议:“如果 Touch ID 失败,就显示一个普通的批准按钮。”对于本来就允许单击的人工授权提示,这可能是正确的。如果失败的 Touch ID 请求本身负责保护凭据保险库的访问,这样做就是错误的。同一个界面可以同时包含这两个概念,但它们必须产生不同的状态变化。
代理协议也应使用独立状态:
awaiting_human_approval表示操作尚未运行,人工可以批准或拒绝已明确标识的请求。awaiting_vault_unlock表示操作无法继续,因为密钥边界处于关闭状态。denied表示网关不会为此请求保留权限。expired表示请求等待时间过长,必须重新提交。
不要把这四种状态都叫作“需要批准”。这句话掩盖了代理最需要知道的事实:它应该等待、停止,还是准备一个新的请求。
合盖模式会移除内置传感器
MacBook 合上屏幕后,内置 Touch ID 传感器在物理上无法访问。Apple 将合盖模式列为 macOS 中内置生物识别传感器不可访问的典型情况:合上的 MacBook 连接外接显示器和键盘后,无法使用内部 Touch ID,除非外接键盘本身带有 Touch ID。
对于运行编程代理的人来说,这并不是什么边缘情况。MacBook 之所以放在桌下或显示器旁边,正是因为它需要长时间保持运行。如果批准设计假定用户随时能摸到电源按钮,它在演示时可能正常,在日常使用中却会失败。
在决定回退行为之前,先记录实际的桌面布局:
| 物理布局 | Touch ID 路径 | 正确的网关行为 |
|---|---|---|
| 笔记本电脑打开 | 可能可以访问内置传感器 | 在控制策略允许时提供 Touch ID。 |
| 笔记本电脑合上,外接键盘不带 Touch ID | 内置传感器不可用 | 不要提示用户扫描。显示控制策略实际允许的批准路径,或者在保险库仍锁定时拒绝依赖密钥的操作。 |
| 笔记本电脑合上,外接键盘带 Touch ID | 外部传感器可能提供 Touch ID | 只有在 macOS 报告生物识别可用后,才提供扫描。 |
| 笔记本电脑合上,Touch ID 键盘断开或没电 | 没有可用的生物识别路径 | 将生物识别批准标记为不可用,并遵循传感器不可用时的同一规则。 |
表格中最重要的词是“可能”。硬件存在,并不能证明它当前可用。无线键盘可能关机、断开连接、配对到了另一台电脑,或者根本不属于当前用户会话。应用应先向操作系统确认所需策略是否能够运行,然后再显示提示用户触摸传感器的文字。
不要因为进入合盖模式,就自动把操作从按调用批准降级为按会话批准。这种变化会超出眼前的物理问题,并授予比用户看到的更宽权限。如果请求需要按调用决定,就保持按调用。若控制策略允许,提供单击批准;否则根据操作类别让请求等待或失败。
“用户无法扫描”和“用户无法批准”是两回事。使用普通外接键盘的人仍然可以阅读卡片并单击批准按钮。对于设计为单击或 Touch ID 批准的按调用密钥,这已经足够。但它不能解锁由 Touch ID 保护的保险库。界面文字也要同样直接:“批准可用,保险库已锁定”远好于一个笼统的红色失败提示。
扫描失败应让一个请求等待,而不是创造新权限
指纹扫描失败一次很正常。皮肤干燥、手指角度不佳、传感器上有残留物,以及匆忙触碰都可能发生。正确的回应是有边界的重试状态,既不是立即拒绝,也不是让请求无限期保持有效。
Apple 的 LocalAuthentication 文档区分了普通认证失败和生物识别锁定。凭据检查失败会报告 authenticationFailed,而尝试次数过多后会进入另一个独立的锁定状态。网关应保留这种区分,因为两者的恢复路径不同。
对于普通扫描失败,让原始操作在短时间内保持不可变并处于等待状态。用户应看到正在批准的内容、发起请求的代理进程、目标主机或 API、凭据标签,以及有实际意义的操作。代理则应收到机器可读的等待结果,而不是一个伪装成失败的超时。
可以使用这样的响应结构:
{
"status": "awaiting_human_approval",
"request_id": "apr_7f3c",
"reason": "biometric_retry",
"expires_at": "2026-07-22T18:42:00Z",
"retry_after_ms": 1500,
"action_started": false
}
request_id 必须绑定完整的拟执行操作,而不只是凭据。如果代理先请求运行 git push,之后在用户重试 Touch ID 时更改远程仓库、分支或命令,那么这就是另一个请求。应拒绝它,或要求创建新的批准卡。因为同一个进程仍然存在就复用批准,正是把无害的重试变成混淆代理漏洞的方式。
设置两个限制。第一,要对界面尝试进行足够的限速,避免有故障的代理不断重新打开会吸引注意力的提示。第二,在短暂且清晰可见的时间后让等待中的请求过期。用户十分钟后回来时,应针对重新渲染的请求做决定,因为代理的仓库状态、API 负载或远程系统可能已经改变。
重试状态不应让代理进程持有任何凭据材料。代理可以保留预定执行的命令或请求正文,但网关不能在“等待认证”期间把令牌交出去。只有网关执行已批准的通道操作时,才注入密钥。
团队经常把错误的重试循环放在错误的位置。他们让代理每隔几秒重试整个工具调用。这样会产生重复卡片,增加 API 操作重复执行的机会,也会教会模型把坚持不懈当成绕过犹豫的方法。等待中的请求由网关负责管理。代理可以轮询或等待这个请求 ID,但在首个请求过期或被拒绝之前,不应自行制造新请求。
传感器锁定意味着生物识别路径已经结束
传感器锁定并不是“再按一次指纹”就能解决的请求,而是 macOS 在告知用户:生物识别已被禁用,必须完成操作系统要求的恢复步骤。Apple 将 biometryLockout 记录为多次失败后进入的状态,并说明需要密码才能解锁生物识别。
这对代理操作有直接影响:停止提示 Touch ID。操作系统已经锁定传感器后,继续要求用户扫描指纹既具有误导性,也可能让用户反复用力触碰传感器。应告诉用户 macOS 需要账户认证来恢复 Touch ID,然后根据操作类别结束或暂停网关请求。
不要把账户密码悄悄当成 Touch ID 的等价物。Apple 的 deviceOwnerAuthentication 策略可以使用 Touch ID、附近已配对的 Apple Watch,或用户的 macOS 密码。而仅生物识别策略在生物识别不可用、未注册或已锁定时会失败。两者都是有效的系统策略,但作出的安全承诺不同。
如果保险库门规定 Touch ID 是解锁条件,那么密码回退就改变了这道门。你可以在另一种产品设计中决定 macOS 密码是可接受的替代认证方式,但必须在保险库边界处明确声明并实现这一选择。不要因为框架提供了方便的默认值,就意外继承这种行为。
对于绑定 Touch ID 的保险库,锁定应为当前所有等待中的依赖密钥调用返回终止性结果:
status: denied
reason: vault_authentication_unavailable
recovery: authenticate with macOS to restore Touch ID, then submit a new request
action_started: false
这比临时的扫描失败更严格。用户必须在网关批准流程之外完成恢复操作。在恢复期间继续保留旧请求,会产生难看的歧义:之后输入账户密码,是批准了原来的 SSH 命令,还是只是恢复了传感器?答案必须明确:它只恢复了传感器。代理必须重新请求该操作。
对于不依赖保险库解锁的批准,可以选择不同结果。如果策略允许,按会话授权卡可以继续作为单击决定使用,前提是操作本身不需要被锁定的密钥。界面应明确指出失败的具体对象。“Touch ID 已锁定,仍可单击批准”是清晰一致的消息;“认证失败”则不是。
让等待还是停止成为操作自身的属性
不要只根据错误代码决定是否等待。应结合操作的后果、时效要求以及凭据边界的状态来决定。同一个不可用的传感器,可能让无害的状态查询等待,让不可逆的基础设施命令停止,也可能让依赖保险库的请求在保险库解锁前直接失败。
我使用三类操作。
第一类:短暂等待人工响应
只有同时满足以下条件时,才让操作等待:
- 网关尚未开始操作,也没有注入凭据。
- 请求具有稳定身份,并显示明确的过期时间。
- 批准后重新执行不会让用户感到意外,因为目标和负载保持不变。
- 操作可逆、只读,或具有足够幂等性,短暂延迟不会改变其含义。
例如,读取私有软件包版本、获取仓库受保护分支的设置,或发起一个明确标注的模拟 API 请求。即便如此,等待也必须由网关管理,而不是放进代理的重试循环。
第二类:停止并要求新请求
如果延迟会改变命令的实际含义,就应停止。部署、生产数据库迁移、强制推送、凭据轮换、支付扣款,或删除数据的 SSH 命令,都不应带着潜在批准一直等待。用户稍后再次看到它时,应获得一张反映当前环境的新卡片。
如果请求包含临时值,也应停止。签名 API 请求、一次性部署产物、短时有效的 URL,或本地工作区已经改变的命令,都不应从过时意图中恢复。代理进程尚未退出,并不能证明它仍然想做完全相同的事情。
第三类:保险库关闭时立即拒绝
锁定的保险库优先于便利。如果拟执行的 HTTP 调用或 SSH 命令需要存储的密钥,而保险库门处于锁定状态,就应拒绝操作,不要把它排队等待解锁后自动执行。用户可以先解锁保险库,然后让代理提交新请求。这样可以保留清晰的因果记录:先解锁,再提交,最后执行。
这正是 Sallyport 固定决策阶梯的价值所在。保险库锁定时,它的保险库门会拒绝所有操作;解锁后,再由按会话授权和按调用批准处理请求。策略不会试图判断延迟中的 curl 是否足够无害,可以在生物识别事件发生后重新唤醒。
一个诱人的替代方案是执行队列,等用户触碰传感器后自动唤醒。它很受欢迎,因为演示效果流畅。但在真实使用中,它会把认证变成触发一批可能已经不再符合用户意图的工作的开关。批准应该释放一个用户仍然看得见的请求,而不是清空用户离开期间积累的队列。
外接 Touch ID 键盘需要可用性检查
外接 Touch ID 键盘解决了合盖模式下的一个问题,却增加了另一个依赖。批准发生时,键盘必须存在,并且在当前 Mac 会话中可用。应把这视为实时条件,而不是一次性设置事实。
Apple 的 LocalAuthentication 错误包括可拆卸生物识别配件的 biometryDisconnected 和 biometryNotPaired。这些代码很重要,因为它们能区分硬件缺失和用户认证失败。断开的键盘不应消耗重试次数,也不应计入用户失败率。
界面和协议应分别处理以下四种状态:
| 状态 | 用户看到的内容 | 代理收到的内容 |
|---|---|---|
| 传感器就绪 | 清晰的请求和 Touch ID 操作提示 | awaiting_human_approval |
| 合盖模式下传感器无法访问 | 说明内置传感器无法触达 | approval_path_unavailable,或允许的单击路径 |
| 外部传感器断开 | 提示重新连接、充电,或使用允许的替代批准方式 | approval_path_unavailable |
| 扫描被拒绝 | 同一个不可变请求和重试提示 | 带有 biometric_retry 的 awaiting_human_approval |
不要把框架原始错误名称直接展示给用户,但要在本地活动记录中保留它们。“外接 Touch ID 键盘不可用”对用户有帮助,LAError.biometryDisconnected 则应留在诊断信息和测试中。
批准卡片也必须能够在没有传感器时操作。这既是安全问题,也是基本的可用性要求。鼠标、触控板、键盘焦点和辅助功能控件仍应允许用户拒绝请求,或选择获准的单击批准。不可访问的生物识别传感器绝不能把用户困在无法回答的提示中。
批准界面必须说明被阻塞的边界
大多数困惑来自一个试图表达所有认证形式的通用弹窗。应根据正在等待的边界拆分消息。
对于按会话请求,先显示发起请求的进程的代码签名权限,然后让用户清楚地选择批准或拒绝。这一刻决定了该代理运行是否可以执行操作。如果 Touch ID 可用,它可以确认这个选择。如果设计允许单击,合盖模式不应把卡片变成死路。
对于按调用密钥,显示准确的操作和凭据标签。只有当单击批准只适用于一个不可变请求并且很快过期时,它才仍然是按调用决定。不要因为桌面上使用 Touch ID 不方便,就让代理把五次调用绑定在一个按钮后面。
对于锁定的保险库,应说明保险库已锁定且操作尚未开始。不要把消息写成代理请求被拒绝,因为用户可能会以为自己需要再次单击。恢复步骤属于保险库规定的认证机制。保险库打开后,任何需要密钥的操作都必须重新提交请求。
良好的审计记录也应区分这些状态变化。例如:
2026-07-22T18:40:12Z request.created id=apr_7f3c channel=ssh action="git push origin main"
2026-07-22T18:40:13Z approval.pending id=apr_7f3c method=touch_id
2026-07-22T18:40:16Z biometric.failed id=apr_7f3c source=built_in_sensor
2026-07-22T18:41:02Z request.expired id=apr_7f3c action_started=false
操作日志不应假装扫描失败就是授权拒绝。那是一次认证尝试失败。请求在未执行的情况下过期了。这些措辞在审查时很重要,尤其是代理说“无法部署”,而操作人员需要知道究竟是系统阻止了它、用户拒绝了它,还是根本没人完成提示。
对于防篡改审计系统,应在把状态变化返回代理之前先记录它。Sallyport 从一个加密、哈希链式的日志中生成 Sessions 和 Activity 日志,其 sp audit verify 命令可以在离线状态下对密文验证哈希链。这样,后续审查人员无需相信代理自己的记录,也能确认请求是过期还是被拒绝。
测试实际桌面,而不只是顺利的 API 路径
能够返回成功和失败代码的 LocalAuthentication 单元测试是必要的,但几乎无法证明批准流程真的可靠。让用户感到不便的失败,往往出现在硬件布局、桌面状态和代理时机交汇的地方。
在宣布流程完成前,先在真实 Mac 上执行以下测试:
- 在笔记本电脑打开时启动代理会话,提交一个按调用请求,拒绝它,然后提交新的请求并批准。确认被拒绝的请求从未执行。
- 合上屏幕盖,连接外接显示器和不带 Touch ID 的键盘。确认界面不会要求用户触摸无法访问的传感器。分别测试允许单击的批准和依赖保险库的请求。
- 使用正常工作的外接 Touch ID 键盘重复测试。在批准等待期间断开键盘或关闭电源。确认请求报告的是硬件不可用,而不是生物识别失败。
- 连续进行失败扫描,直到 macOS 进入锁定状态。确认生物识别提示停止,依赖密钥的请求不会排队等待以后执行,并且恢复后必须重新提交操作。
- 让等待中的请求自然过期。在发送新请求前更改仓库分支、命令参数或 API 负载。确认新的提案获得不同的请求 ID 和新的人工决定。
每次测试后都检查日志。你应看到一次请求创建事件、一系列状态变化,以及一次执行事件或完全没有执行事件。一次批准信号对应多次执行,说明存在重放或重试缺陷。缺少终止事件则意味着支持人员只能猜测代理是否仍在等待。
还要测试取消。Touch ID 不可用时,用户必须仍能拒绝请求;代理必须能够放弃等待中的请求;应用关闭时必须使仍然有效的批准失效。Apple 在 LocalAuthentication 中区分用户取消、应用取消和系统取消。即使界面把它们都归为易懂的“已取消”,审计模型也应保留这种区分。
可靠的回退路径正常工作时几乎让人觉得无聊。界面如实说明传感器状态,代理收到可以遵循的状态,密钥留在保险库中,没有任何操作会因为用户合上笔记本电脑而逃逸。这就是应坚持的标准:每一次物理故障都导向一个明确且不会扩大权限的结果。
常见问题
MacBook 在合盖模式下还能使用 Touch ID 吗?
合盖模式会使笔记本电脑内置的 Touch ID 传感器无法使用,因为屏幕盖已经合上。Apple 将其记录为内置传感器不可访问的问题。如果外接键盘自带 Touch ID,Touch ID 仍可能可用。
Touch ID 扫描失败后,代理应该怎么做?
扫描失败表示生物识别没有验证通过。让请求在一个短暂且清晰可见的重试窗口内保持等待,但不要执行操作,也不要把失败静默转换成批准。
应用能否用密码绕过 Touch ID 锁定?
不能。传感器锁定表示 macOS 要求用户使用账户密码完成验证,之后生物识别功能才能恢复。应将其视为设备认证状态发生了变化,而不是一次普通的扫描失败。
单击批准等同于解锁凭据保险库吗?
这是两种不同的控制。批准决定某个特定代理或调用是否可以继续,保险库门则决定任何依赖密钥的操作是否能够运行。保险库无法解锁时,单击批准不能替代解锁,否则会削弱这道边界。
代理应该等待 Touch ID 恢复可用吗?
只有在操作尚未执行、具有明确的过期时间,并且可以使用相同的请求详情安全恢复时,才应等待 Touch ID 恢复可用。排队中的批准绝不能变成代理替换后续请求的许可。
哪些代理操作应该停止,而不是等待批准?
对于具有破坏性、时效性强、之后难以准确识别,或依赖已锁定保险库的请求,应直接停止。只有有明确边界、不会执行操作,并且具备可供人理解的恢复路径的请求,才适合等待。
外接 Touch ID 键盘断开时,批准界面应该怎么处理?
界面需要显示清晰的状态,提供重新连接或给键盘充电的办法,并允许取消等待中的请求。不要因为之前见到过某个蓝牙设备,就暗示已配对的键盘当前可用。
macOS 支持密码回退,是否意味着所有 Touch ID 批准都应该接受密码?
不一定。macOS 可以通过通用的设备所有者认证策略提供账户密码回退,但如果产品承诺保险库必须由 Touch ID 保护,就必须明确决定密码回退是否仍符合这一安全承诺。这是两种不同的设计。
Touch ID 多次失败后,用户应该怎么做?
当操作系统要求时,使用 macOS 账户密码恢复生物识别功能。至于代理操作本身,应遵循产品明确规定的门槛和批准规则,不要把密码提示自动当成操作许可。
团队应该测试哪些 Touch ID 批准回退场景?
测试人们实际使用的物理环境:屏幕盖打开、合盖并连接不带 Touch ID 的键盘、合盖并连接带 Touch ID 的键盘、键盘断开、连续扫描失败,以及生物识别锁定。分别记录每种情况下请求是等待、过期还是被拒绝。