资讯详情

OWASP MASTG:使用 iOS Keychain Services 实现基于生物认证的本地认证

📅 2026/10/8 22:55:38 | 华诺云谱 👁 阅读
OWASP MASTG:使用 iOS Keychain Services 实现基于生物认证的本地认证
文档教程网络安全【免费下载链接】mastgThe OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.项目地址https://gitcode.com/gh_mirrors/ow/mastg点击查看免费下载导读本文围绕 OWASP Mobile Application Security Testing GuideMASTG中 MASTG-KNOW-0057 的核心知识系统讲解如何用 iOS Keychain ServicesSecurity.framework把秘密数据认证 Token、密钥等与 Touch ID / Face ID 绑定存储形成认证通过才能取出数据的安全检索路径。读完本文你将掌握SecAccessControlCreateWithFlags、SecItemAdd、SecItemCopyMatching的完整用法、各访问控制标志的安全含义以及如何结合 MASTG 测试用例与 Demo 从源码和二进制两个层面验证实现是否安全。本地认证的两种实现路线在 iOS 上实现本地认证开发者有两条路线二者常被混淆LocalAuthentication.framework高层 API通过LAContext.evaluatePolicy弹出认证对话框Touch ID / Face ID / 设备密码只返回成功/失败布尔值应用拿不到任何与生物特征相关的数据。参见 MASTG-KNOW-0056。Security.frameworkKeychain Services底层 API可以在把敏感数据写入钥匙串时挂上访问控制Access Control只有用户通过生物认证后才能读取。访问控制在系统层面强制执行无法轻易绕过。MASTG 的核心观点见 Document/0x06f-Testing-Local-Authentication.md是只依赖 LocalAuthentication 的事件型认证是不够的因为它只返回一个布尔值攻击者通过运行时 hook例如把evaluatePolicy的结果强制改成True即可绕过而 Keychain 方式把认证内嵌进取数据这一不可分割的检索路径中认证不通过就拿不到数据。Apple 也推荐在可能的情况下优先使用高层 API但就本地认证而言保护敏感数据时应当使用 Keychain Services。对应地MASTG 在 MASTG-TEST-0266 中明确如果应用对敏感资源Token、密钥仅用LAContext.evaluatePolicy做访问控制而不用 Keychain API 并要求用户在场user presence测试即判失败。SecAccessControl把认证绑定到钥匙串条目Keychain 允许在保存条目时携带一个特殊的SecAccessControl属性。设置了该属性后只有用户通过了 Touch ID 认证或按属性参数允许回退到密码才能访问该条目。创建 AccessControl 对象SecAccessControlCreateWithFlags是这一切的入口其完整签名如下func SecAccessControlCreateWithFlags( _ allocator: CFAllocator?, // 内存分配器传 kCFAllocatorDefault或 nil _ protection: CFTypeRef, // 数据保护类别kSecAttrAccessible 系列 _ flags: SecAccessControlCreateFlags, // 访问控制标志 _ error: UnsafeMutablePointerUnmanagedCFError?? ) - SecAccessControl?在 MASTG-KNOW-0057 的示例中使用如下组合var error: UnmanagedCFError? guard let accessControl SecAccessControlCreateWithFlags( kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, // 保护类别 SecAccessControlCreateFlags.biometryCurrentSet, // 访问控制标志 error ) else { // failed to create AccessControl object return }两个参数各自的作用如下。protection保护类别决定钥匙串条目在设备生命周期中的可访问时机常用值包括值含义kSecAttrAccessibleWhenUnlocked设备解锁期间可访问默认kSecAttrAccessibleAfterFirstUnlock设备首次解锁后始终可访问含锁屏状态kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly仅当设备设置了密码时才允许访问且条目不随 iCloud 同步到其他设备kSecAttrAccessibleWhenUnlockedThisDeviceOnly/kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly相应的仅本设备变体...ThisDeviceOnly系列的关键差异是不会同步到其他 iOS 设备适合高敏感数据。MASTG 在测试指南MASTG-TEST-0064中建议要确保生物认证可用SecAccessControlCreateWithFlags应搭配kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly或kSecAttrAccessibleWhenPasscodeSet保护类别。flags访问控制标志决定解锁该条目需要什么认证方式。以 MASTG-KNOW-0057 示例使用的biometryCurrentSet为例它要求访问时必须通过生物认证Touch ID / Face ID且仅限当前已录入enrolled的指纹/面容可解锁一旦用户后续新增指纹或面容该钥匙串条目自动失效。这意味着只有条目创建时已录入生物特征的用户才能解开它可有效防止攻击者拿到设备密码后录入自己的指纹/面容来解锁应用内数据。注意iOS 不支持条目的时效性原文档特别强调了一个平台差异!!! note与 macOS 和 Android 不同iOS 不支持钥匙串条目可访问性的时效性temporality当进入钥匙串时没有额外的安全检查例如设置了kSecAccessControlUserPresence或类似标志那么一旦设备解锁条目中的密钥就可被访问。换句话说设备是否解锁与用户是否通过认证是两回事如果条目只设置了保护类别而没有访问控制标志那么设备解锁后任何进程都可能读到该条目必须在条目上显式挂上 Access Control 标志才能把访问与用户认证绑定。保存受认证保护的条目完整示例原文档给出的保存流程分三步创建 AccessControl → 构造查询字典 → 调用SecItemAdd。// 1. Create the AccessControl object that will represent authentication settings var error: UnmanagedCFError? guard let accessControl SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, SecAccessControlCreateFlags.biometryCurrentSet, error) else { // failed to create AccessControl object return } // 2. Create the keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute var query: [String: Any] [:] query[kSecClass as String] kSecClassGenericPassword query[kSecAttrLabel as String] com.me.myapp.password as CFString query[kSecAttrAccount as String] OWASP Account as CFString query[kSecValueData as String] test_strong_password.data(using: .utf8)! as CFData query[kSecAttrAccessControl as String] accessControl // 3. Save the item let status SecItemAdd(query as CFDictionary, nil) if status noErr { // successfully saved } else { // error while saving }对其中几个关键点做源码级说明kSecAttrAccessControl与kSecAttrAccessible互斥查询字典中一旦放了kSecAttrAccessControl就不能再放kSecAttrAccessible。这是因为保护类别信息已经作为第一个参数传给了SecAccessControlCreateWithFlags并由返回的SecAccessControl对象携带。kSecClass选择条目类型kSecClassGenericPassword表示通用密码条目最常用其他还有kSecClassInternetPassword、kSecClassCertificate、kSecClassKey、kSecClassIdentity。kSecAttrAccount/kSecAttrLabel分别用于标识条目的账号与标签。检索时kSecAttrAccount是重要的匹配键因此示例中的OWASP Account与后面的检索查询保持一致很重要注意原文档检索示例里写的是My Name实际项目中应保持同一常量以免查不到。kSecValueData要保护的载荷这里演示的是字符串test_strong_password的 UTF-8 数据。真实场景中通常是服务端下发的认证 Token、用于派生加密密钥的随机数等。返回状态码SecItemAdd返回OSStatusnoErr即errSecSuccess表示成功常见错误还包括errSecDuplicateItem条目已存在、errSecParam参数不合法等实践中常先调用SecItemDelete清理旧条目再写入仓库 Demo MASTG-DEMO-0043 的 MastgTest.swift 正是这么做的。读取条目由 Keychain 触发认证对话框写入之后读取时 Keychain Services 会自动弹出认证对话框无需应用自己调用LAContext并依据用户是否提供了合适的指纹/面容返回数据或失败// 4. Now we can request the saved item from the keychain. Keychain services will present the authentication dialog to the user and return data or nil depending on whether a suitable fingerprint was provided or not. // 5. Create the query var query [String: Any]() query[kSecClass as String] kSecClassGenericPassword query[kSecReturnData as String] kCFBooleanTrue query[kSecAttrAccount as String] My Name as CFString query[kSecAttrLabel as String] com.me.myapp.password as CFString query[kSecUseOperationPrompt as String] Please, pass authorisation to enter this area as CFString // 6. Get the item var queryResult: AnyObject? let status withUnsafeMutablePointer(to: queryResult) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) } if status noErr { let password String(data: queryResult as! Data, encoding: .utf8)! // successfully received password } else { // authorization not passed }参数要点kSecReturnData设为truekCFBooleanTrue后SecItemCopyMatching通过queryResult返回条目的数据载荷kSecUseOperationPrompt自定义认证对话框的提示文案例如Please, pass authorisation to enter this area应使用面向用户的可读措辞认证失败的表现若用户取消认证或提供了不匹配的指纹status不为noErr典型如errSecAuthFailed此时绝不能回退到任何降级路径读取数据现代实现中还可以通过kSecUseAuthenticationContext传入自定义LAContext用于设置localizedReason或touchIDAuthenticationAllowableReuseDuration可复用时长不传也没关系Keychain Services 内部会自动使用LocalAuthentication框架完成提示参见 MASTG-DEMO-0043 源码注释。访问控制标志选型从 MASTG 测试看安全性阶梯原文档示例选用biometryCurrentSetMASTG 的 V1 测试指南MASTG-TEST-0064给出了完整的标志对照安全强度从高到低可归纳为标志行为安全含义kSecAccessControlBiometryCurrentSetiOS 11.3 前为kSecAccessControlTouchIDCurrentSet仅当前已录入生物特征可解锁新增指纹/面容后条目自动失效最严格攻击者事后录入的生物特征无法解锁代价是用户重新录入后需重新写入条目kSecAccessControlBiometryAnyiOS 11.3 前为kSecAccessControlTouchIDAny任意已录入生物特征可解锁条目在重新录入后仍然有效便利性优先若攻击者能把指纹/面容录入设备同样能解锁条目kSecAccessControlUserPresence生物认证失败或未配置时回退到设备密码更弱密码更易被偷看shoulder surfing等方式窃取kSecAccessControlDevicePasscode仅要求设备密码无生物认证绑定属于最弱绑定MASTG 还从两个角度把回退到密码和未绑定当前生物特征固化为可执行的测试用例MASTG-TEST-0268静态/MASTG-TEST-0269动态检测应用是否对敏感数据使用kSecAccessControlUserPresence或kSecAccessControlDevicePasscode标志。虽然这不天然是漏洞但在金融、政务、医疗等高安全场景中属于降低安全姿态的弱点/加固问题动态版通过 hookSecAccessControlCreateWithFlags观察运行期实际传入的 flags。MASTG-TEST-0270检测敏感条目是否缺少kSecAccessControlBiometryCurrentSet标志。若缺失攻击者拿到设备密码后可在系统设置中添加新指纹/面容从而在应用内通过认证。对应地MASTG-DEMO-0044 用 Frida 展示了运行期观察SecAccessControlCreateWithFlags(..., kSecAccessControlUserPresence)的全过程由于该 Demo 的 Token 需要生物认证保护却允许回退到密码测试判为失败并给出修复建议——改用kSecAccessControlBiometryCurrentSet或kSecAccessControlBiometryAny其中前者最安全。为什么 Keychain 认证比 LAContext 更难绕过回到 MASTG-KNOW-0057 的出发点Keychain 认证的价值在于它是进程外的安全数据检索路径。本地认证永远不应成为最终防线——正如 Document/0x06f-Testing-Local-Authentication.md 所述认证结果必须最终由远端端点或密码学原语背书。Keychain 方案正是在本地与密码学之间架起桥梁认证通过后取出的 Token/密钥本身就可用于向远端证明身份或解密数据。对攻击者而言绕过LAContext.evaluatePolicy只需 hook 其返回值为true——MASTG 的绕过技术 MASTG-TECH-0135 展示了用 objection 一行命令即可完成objection -n MASTestApp start ios ui biometrics_bypass但面对挂载了 Access Control 的 Keychain 条目由于认证发生在 Keychain 内部Secure Enclave 参与简单的布尔值替换无法让SecItemCopyMatching吐出数据因此绕过成本显著更高。这也正是 MASTG-TEST-0266 的判定逻辑凡是对敏感资源只信任一个布尔值的实现均应判失败并改用 Keychain API。实战验证如何检查你的实现是否安全MASTG 为 Keychain 相关的本地认证提供了一整套静态与动态验证流程对应测试用例的 Steps 均引用 MASTG-TECH-0058 解包二进制、MASTG-TECH-0066 做静态分析动态验证则用 MASTG-TECH-0056 安装应用、MASTG-TECH-0095 进行 hook静态检查在二进制中定位SecAccessControlCreateWithFlags的调用点确认传给 flags 参数的枚举值。如 MASTG-DEMO-0043 所示该函数第三个参数flags在 ARM64 上位于w2寄存器mov w2, 1即对应kSecAccessControlUserPresence枚举值 1。动态检查运行期 hookSecAccessControlCreateWithFlags与SecItemCopyMatching收集实际传入的 flags 与触发认证的调用路径见 MASTG-TEST-0269。对照检查清单逐项核验敏感 Token/密钥是否走 Keychain 而非仅LAContext布尔判断MASTG-TEST-0266是否使用了kSecAccessControlBiometryCurrentSet绑定录入时的生物特征MASTG-TEST-0270是否误用kSecAccessControlUserPresence/kSecAccessControlDevicePasscode造成密码回退MASTG-TEST-0268、MASTG-TEST-0269保护类别是否为...ThisDeviceOnly系列避免条目被同步到其他设备。此外Keychain 在数据存储维度同样关键MASTG-TEST-0300 将使用 Keychain API 存取敏感数据视为避免明文落盘私有存储的正确做法并关注 Keychain 密钥在加密前的管理方式——即敏感数据要么加密后写入私有存储要么直接由 Keychain 保管两者都是可接受的结论。最佳实践小结综合 MASTG-KNOW-0057 与仓库中的测试、Demo 证据落地到真实应用时应遵循敏感数据一律走 Keychain认证 Token、签名私钥等放入钥匙串条目用SecAccessControlCreateWithFlags挂上访问控制形成认证即取数的原子路径标志优先选kSecAccessControlBiometryCurrentSet高安全场景下拒绝密码回退并在用户重新录入生物特征后引导重新写入条目保护类别选kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly保证设备设置密码是前置条件且条目不跨设备同步注意互斥约束查询字典中kSecAttrAccessControl与kSecAttrAccessible不可同时出现保护类别只在SecAccessControlCreateWithFlags中指定检索时善用kSecUseOperationPrompt提供明确提示并严格处理非noErr状态禁止任何降级读取牢记平台差异iOS 钥匙串条目没有时效性设备解锁后若无 Access Control 标志数据即处于可访问状态因此标志设置不是可选项而是安全底线。赞分享文档教程网络安全【免费下载链接】mastgThe OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.项目地址https://gitcode.com/gh_mirrors/ow/mastg点击查看免费下载相关推荐使用 radare2 静态分析 iOS Keychain 生物认证回退kSecAccessControlUserPresence 实战解析MASTG-DEMO-0043使用 radare2 静态分析 iOS Keychain 生物认证回退kSecAccessControlUserPresence 实战解析MASTG DEM文档教程网络安全OWASP MASTG iOS 实战用 Frida 动态检测 LAContext.evaluatePolicy 事件绑定式生物识别认证MASTG-DEMO-0042OWASP MASTG iOS 实战用 Frida 动态检测 LAContext.evaluatePolicy 事件绑定式生物识别认证MASTG DEMO文档教程网络安全OWASP MASTG 实践指南使用 CryptoObject 为 Android 生物识别认证建立密码学绑定MASTG-BEST-0036OWASP MASTG 实践指南使用 CryptoObject 为 Android 生物识别认证建立密码学绑定MASTG BEST 0036 导读 本指南文档教程网络安全创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑