swift-security-expert by ivan-magda/swift-security-skill
npx skills add https://github.com/ivan-magda/swift-security-skill --skill swift-security-expert理念: 非主观、注重正确性。本技能提供事实、已验证的模式和 Apple 文档化的最佳实践——而非架构指令。它以 iOS 13+ 作为最低部署目标,提供面向 iOS 17+ 的现代建议以及展望至 iOS 26(后量子时代)的前瞻性指导。每个代码模式都基于 Apple 文档、DTS 工程师帖子(Quinn "The Eskimo!")、WWDC 会议和 OWASP MASTG——绝不单凭记忆。
本技能是什么: 一份用于审查、改进和实现 Apple 平台上的密钥链操作、生物识别认证、CryptoKit 加密、凭证生命周期管理、证书信任和合规性映射的参考资料。
本技能不是什么: 网络指南、服务器端安全参考或应用传输安全手册。TLS 配置、服务器证书管理和后端认证架构不在本技能范围内,除非它们直接涉及客户端密钥链或信任 API。
确定用户意图,然后遵循匹配的分支。如果意图不明确,请询问。
┌─────────────────────┐
│ 任务是什么? │
└─────────┬───────────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌───────────┐ ┌────────────┐
│ 审查 │ │ 改进 │ │ 实现 │
│ │ │ │ │ │
│ 审计 │ │ 迁移/ │ │ 从零开始 │
│ 现有代码│ │ 现代化 │ │ 构建 │
│ │ │ 现有代码 │ │ │
└────┬────┘ └─────┬─────┘ └─────┬──────┘
│ │ │
▼ ▼ ▼
运行顶级审查 识别差距 识别适用的
检查清单(见下文) (遗留存储? 领域,
对照代码。 错误的 API? 加载参考文件,
标记每个项目为 缺少认证?) 遵循 ✅ 模式。
✅ / ❌ / 加载迁移 + 实现时使用
⚠️ 不适用。 领域特定的 添加或更新模式、
对于每个 ❌, 参考文件。 正确的错误处理,
引用参考文件 遵循 ✅ 模式, 以及从一开始就
和具体章节。 用领域检查清单 正确的访问控制。
验证。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
目标: 系统地评估现有密钥链/安全代码的正确性、安全性和合规性。
流程:
common-anti-patterns.md 中的所有 10 个条目扫描代码。特别注意:将秘密存储在 UserDefaults 中(#1)、硬编码密钥(#2)、将 LAContext.evaluatePolicy() 作为唯一的认证门控(#3)、忽略 OSStatus(#4)。compliance-owasp-mapping.md 中的类别 M1、M3、M9、M10。用于审查的关键参考文件:
common-anti-patterns.md(核心——涵盖 10 种最危险的模式)compliance-owasp-mapping.md(如果合规性相关)目标: 将现有代码从不安全的存储、已弃用的 API 或遗留模式升级到当前的最佳实践。
流程:
* 不安全存储 → 密钥链:加载 `migration-legacy-stores.md` + `credential-storage-patterns.md`
* 遗留 Security 框架 → CryptoKit:加载 `cryptokit-symmetric.md` 或 `cryptokit-public-key.md` + `migration-legacy-stores.md`
* RSA → 椭圆曲线:加载 `cryptokit-public-key.md`(RSA 迁移部分)
* GenericPassword → InternetPassword(自动填充):加载 `keychain-item-classes.md`(迁移部分)
* 仅使用 LAContext → 密钥链绑定的生物识别:加载 `biometric-authentication.md`
* 基于文件的密钥链 → 数据保护密钥链(macOS):加载 `keychain-fundamentals.md`(TN3137 部分)
* 单一应用 → 共享密钥链(扩展):加载 `keychain-sharing.md`
* 叶子证书固定 → SPKI/CA 固定:加载 `certificate-trust.md`
2. 遵循相关参考文件中的迁移模式。每个迁移部分都包括:迁移前验证、原子迁移步骤、遗留数据安全删除、迁移后验证。
迁移完成后,运行参考文件中的领域特定检查清单。
使用 testing-security-code.md 中的指导验证没有回归。
目标: 从一开始就正确构建新的密钥链/安全功能。
流程:
testing-security-code.md 添加测试——单元测试使用基于协议的抽象,集成测试在设备上使用真实的密钥链。领域选择指南:
| 如果任务涉及… | 加载这些参考文件 |
|---|---|
| 存储/读取密码或令牌 | keychain-fundamentals.md + credential-storage-patterns.md |
选择使用哪个 kSecClass | keychain-item-classes.md |
| 设置项目的可访问时间 | keychain-access-control.md |
| Face ID / Touch ID 门控 | biometric-authentication.md + keychain-access-control.md |
| 硬件支持的密钥 | secure-enclave.md |
| 加密 / 哈希数据 | cryptokit-symmetric.md |
| 签名 / 密钥交换 / HPKE | cryptokit-public-key.md |
| OAuth 令牌 / API 密钥 / 登出 | credential-storage-patterns.md |
| 在应用和扩展之间共享 | keychain-sharing.md |
| TLS 固定 / 客户端证书 | certificate-trust.md |
| 替换 UserDefaults / plist 中的秘密 | migration-legacy-stores.md |
| 为安全代码编写测试 | testing-security-code.md |
| 企业审计 / OWASP 合规 | compliance-owasp-mapping.md |
这七条规则不容妥协。每个密钥链/安全实现都必须满足所有规则。
1. 绝不忽略 OSStatus。 每个 SecItem* 调用都返回一个 OSStatus。使用详尽的 switch 语句,至少覆盖:errSecSuccess、errSecDuplicateItem (-25299)、errSecItemNotFound (-25300)、errSecInteractionNotAllowed (-25308)。静默丢弃返回值是大多数密钥链错误的根源。→ keychain-fundamentals.md
2. 绝不将 LAContext.evaluatePolicy() 用作独立的认证门控。 这会返回一个 Bool,在运行时可以通过 Frida 轻易地打补丁绕过。生物识别认证必须与密钥链绑定:将秘密存储在带有 .biometryCurrentSet 的 SecAccessControl 后面,然后在 SecItemCopyMatching 期间让密钥链提示 Face ID/Touch ID。密钥链在安全隔区中处理认证——没有可打补丁的 Bool。→ biometric-authentication.md
3. 绝不将秘密存储在 UserDefaults、Info.plist、.xcconfig 或 NSCoding 归档中。 这些会产生可从未加密备份中读取的明文文件。密钥链是 Apple 认可的存储凭证的唯一位置。→ credential-storage-patterns.md、common-anti-patterns.md
4. 绝不在 @MainActor 上调用 SecItem*。 每次密钥链调用都是一次到 securityd 的 IPC 往返,会阻塞调用线程。使用专用的 actor(iOS 17+)或串行 DispatchQueue(iOS 13–16)进行所有密钥链访问。→ keychain-fundamentals.md
5. 始终显式设置 kSecAttrAccessible。 系统默认值(kSecAttrAccessibleWhenUnlocked)会破坏所有后台操作,并且可能与你的威胁模型不匹配。选择满足你访问模式的最严格的类别。对于后台任务:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly。对于最高敏感度:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly。→ keychain-access-control.md
6. 始终使用添加或更新模式。 先 SecItemAdd,然后在遇到 errSecDuplicateItem 时进行 SecItemUpdate。绝不先删除再添加(会产生竞争窗口并破坏持久引用)。绝不调用 SecItemAdd 而不处理重复项的情况。→ keychain-fundamentals.md
7. 在 macOS 上始终以数据保护密钥链为目标。 在 macOS 目标上,为每个 SecItem* 调用设置 kSecUseDataProtectionKeychain: true。没有它,查询会静默路由到遗留的基于文件的密钥链,后者行为不同,忽略不支持的属性,并且无法使用生物识别保护或安全隔区密钥。Mac Catalyst 和 iOS-on-Mac 会自动执行此操作。→ keychain-fundamentals.md
| 常量 | 何时可解密 | 在备份中保留 | 在设备迁移中保留 | 后台安全 | 使用场景 |
|---|---|---|---|---|---|
WhenPasscodeSetThisDeviceOnly | 已解锁 + 已设置密码 | ❌ | ❌ | ❌ | 最高安全级别的秘密;移除密码时会被移除 |
WhenUnlockedThisDeviceOnly | 已解锁 | ❌ | ❌ | ❌ | 设备绑定且不需要在后台使用的秘密 |
WhenUnlocked | 已解锁 | ✅ | ✅ | ❌ | 可同步的秘密(系统默认值——避免隐式使用) |
AfterFirstUnlockThisDeviceOnly | 首次解锁后 → 重启 | ❌ | ❌ | ✅ | 后台任务、推送处理器、设备绑定 |
AfterFirstUnlock | 首次解锁后 → 重启 | ✅ | ✅ | ✅ | 必须在恢复后保留的后台任务 |
已弃用(绝不使用): kSecAttrAccessibleAlways、kSecAttrAccessibleAlwaysThisDeviceOnly —— 已在 iOS 12 弃用。
经验法则: 需要后台访问(推送处理器、后台刷新)?从 AfterFirstUnlockThisDeviceOnly 开始。仅前台使用?从 WhenUnlockedThisDeviceOnly 开始。对于高价值秘密,收紧到 WhenPasscodeSetThisDeviceOnly。仅当需要 iCloud 同步或备份迁移时,才使用非 ThisDeviceOnly 的变体。
| 需求 | 算法 | 最低 iOS | 备注 |
|---|---|---|---|
| 哈希数据 | SHA256 / SHA384 / SHA512 | 13 | SHA3_256/SHA3_512 在 iOS 18+ 可用 |
| 验证数据(MAC) | HMAC<SHA256> | 13 | 始终使用恒定时间比较进行验证(内置) |
| 加密数据(已验证) | AES.GCM | 13 | 256 位密钥,96 位 nonce,128 位标签。切勿对同一密钥重用 nonce |
| 加密数据(移动端优化) | ChaChaPoly | 13 | 在没有 AES-NI 的设备上表现更好(旧款 Apple Watch) |
| 签名数据 | P256.Signing / Curve25519.Signing | 13 | 互操作性用 P256,性能用 Curve25519 |
| 密钥协商 | P256.KeyAgreement / Curve25519.KeyAgreement | 13 | 始终通过 HKDF 派生对称密钥——切勿使用原始共享秘密 |
| 混合公钥加密 | HPKE | 17 | 替代手动 ECDH+HKDF+AES-GCM 链 |
| 硬件支持的签名 | SecureEnclave.P256.Signing | 13 | 仅限 P256;密钥永不离开硬件 |
| 后量子密钥交换 | MLKEM768 | 26 | 正式验证(ML-KEM FIPS 203) |
| 后量子签名 | MLDSA65 | 26 | 正式验证(ML-DSA FIPS 204) |
| 密码 → 密钥派生 | PBKDF2(通过 CommonCrypto) | 13 | ≥600,000 次迭代 SHA-256(OWASP 2024) |
| 密钥 → 密钥派生 | HKDF<SHA256> | 13 | 提取然后扩展;始终使用 info 参数进行域分离 |
审查代码时,搜索这些模式。任何匹配项都是一个发现。❌ = 用户代码中要检测的不安全模式特征。✅ = 在引用的文件中应用纠正模式。
| 搜索内容 | 反模式 | 严重性 | 参考 |
|---|---|---|---|
UserDefaults.standard.set + token/key/secret/password | 明文凭证存储 | 严重 | common-anti-patterns.md #1 |
| 源代码中硬编码的 base64/hex 字符串(≥16 字符) | 硬编码的加密密钥 | 严重 | common-anti-patterns.md #2 |
evaluatePolicy 附近没有 SecItemCopyMatching | 仅使用 LAContext 的生物识别门控 | 严重 | common-anti-patterns.md #3 |
SecItemAdd 不检查返回值 / OSStatus | 忽略错误代码 | 高 | common-anti-patterns.md #4 |
添加字典中没有 kSecAttrAccessible | 隐式可访问性类别 | 高 | common-anti-patterns.md #5 |
在相同密钥的循环中使用 AES.GCM.Nonce() | 潜在的 nonce 重用 | 严重 | common-anti-patterns.md #6 |
sharedSecret.withUnsafeBytes 没有 HKDF | 将原始共享秘密用作密钥 | 高 | common-anti-patterns.md #7 |
kSecAttrAccessibleAlways | 已弃用的可访问性常量 | 高 | keychain-access-control.md |
SecureEnclave.isAvailable 没有 #if !targetEnvironment(simulator) | 模拟器假阴性陷阱 | 中 | secure-enclave.md |
kSecAttrSynchronizable: true + ThisDeviceOnly | 矛盾的约束 | 中 | keychain-item-classes.md |
SecTrustEvaluate(同步,已弃用) | 遗留的信任评估 | 中 | certificate-trust.md |
kSecClassGenericPassword + kSecAttrServer | 网络凭证使用了错误的类别 | 中 | keychain-item-classes.md |
使用此检查清单对所有 14 个领域进行快速扫描。每个项目都映射到一个或多个参考文件,用于深入调查。对于领域特定的深度检查,请使用每个参考文件底部的摘要检查清单。
1. 秘密存储在密钥链中,而非 UserDefaults/plist/源代码中 —— 没有凭证、令牌或加密密钥存储在 UserDefaults、Info.plist、.xcconfig、硬编码字符串或 NSCoding 归档中。直接违反了 OWASP M9(不安全的数据存储)。→ common-anti-patterns.md #1–2、credential-storage-patterns.md、migration-legacy-stores.md、compliance-owasp-mapping.md
2. 检查每个 OSStatus —— 所有 SecItem* 调用都使用详尽的 switch 或等效方式处理返回码。没有忽略返回值。errSecInteractionNotAllowed 以非破坏性方式处理(稍后重试,绝不删除)。→ keychain-fundamentals.md、common-anti-patterns.md #4
3. 生物识别认证与密钥链绑定 —— 如果使用了生物识别,认证是通过 SecAccessControl + 密钥链访问强制执行的,而不是单独使用 LAContext.evaluatePolicy()。→ biometric-authentication.md、common-anti-patterns.md #3
4. 可访问性类别是显式且正确的 —— 每个密钥链项目都有一个显式的 kSecAttrAccessible 值,与其访问模式匹配(后台与前台,设备绑定与可同步)。没有使用已弃用的 Always 常量。→ keychain-access-control.md
5. 没有在 @MainActor 上调用 SecItem* —— 所有密钥链操作都在专用的 actor 或后台队列上运行。UI 代码、viewDidLoad 或 application(_:didFinishLaunchingWithOptions:) 中没有同步的密钥链访问。→ keychain-fundamentals.md
6. 为每种项目类型使用了正确的 kSecClass —— 网络凭证使用 InternetPassword(而非 GenericPassword)以实现自动填充。加密密钥使用带有正确 kSecAttrKeyType 的 kSecClassKey。应用秘密使用带有 kSecAttrService + kSecAttrAccount 的 GenericPassword。→ keychain-item-classes.md
7. 正确使用 CryptoKit —— 同一密钥绝不重用 nonce。ECDH 共享秘密在用作对称密钥之前始终通过 HKDF 派生。SymmetricKey 材料存储在密钥链中,而非内存或文件中。加密操作由基于协议的单元测试覆盖。→ cryptokit-symmetric.md、cryptokit-public-key.md、testing-security-code.md
8. 遵守安全隔区约束 —— SE 密钥仅为 P256(经典),绝不导入(始终在设备上生成),设备绑定(无备份/同步)。可用性检查防范模拟器和密钥链访问组授权问题。→ secure-enclave.md
9. 正确配置共享和访问组 —— kSecAttrAccessGroup 使用完整的 TEAMID.group.identifier 格式。应用和扩展之间的授权匹配。没有意外的跨应用数据暴露。→ keychain-sharing.md
10. 证书信任评估是最新的 —— 使用 SecTrustEvaluateAsyncWithError(而非已弃用的同步 SecTrustEvaluate)。固定策略使用 SPKI 哈希或 NSPinnedDomains(而非每年轮换时会中断的叶子证书固定)。→ certificate-trust.md
11. macOS 目标使用数据保护密钥链 —— 所有 macOS SecItem* 调用都包含 kSecUseDataProtectionKeychain: true(Mac Catalyst / iOS-on-Mac 除外,它们会自动执行)。→ keychain-fundamentals.md
---|---|---|---
1 | keychain-fundamentals.md | SecItem* 增删改查、查询字典、OSStatus 处理、基于 actor 的包装器、macOS TN3137 路由 | 严重
2 | keychain-item-classes.md | 五种 kSecClass 类型、复合主键、GenericPassword 与 InternetPassword、ApplicationTag 与 ApplicationLabel | 高
3 | keychain-access-control.md | 七种可访问性常量、SecAccessControl 标志、数据保护层级、NSFileProtection 旁注 | 严重
4 | biometric-authentication.md | 密钥链绑定的生物识别、LAContext 绕过漏洞、注册变更检测、回退链 | 严重
5 | secure-enclave.md | 硬件支持的 P256 密钥、CryptoKit SecureEnclave 模块、持久性、模拟器陷阱、iOS 26 后量子 | 高
6 | cryptokit-symmetric.md | SHA-2/3 哈希、HMAC、AES-GCM/ChaChaPoly 加密、SymmetricKey 管理、nonce 处理、HKDF/PBKDF2 | 高
7 | cryptokit-public-key.md | ECDSA 签名、ECDH 密钥协商、HPKE(iOS 17+)、ML-KEM/ML-DSA 后量子(iOS 26+)、曲线选择 | 高
8 | credential-storage-patterns.md | OAuth2/OIDC 令牌生命周期、API 密钥存储、刷新令牌轮换、运行时秘密获取、登出清理 | 严重
9 | keychain-sharing.md | 访问组、Team ID 前缀、应用扩展、Keychain Sharing 与 App Groups 授权、iCloud 同步 | 中
10 | certificate-trust.md | SecTrust 评估、SPKI/CA/叶子证书固定、NSPinnedDomains、客户端证书(mTLS)、信任策略 | 高
11 | migration-legacy-stores.md | UserDefaults/plist/NSCoding → 密钥链迁移、安全删除、首次启动清理、版本化迁移 | 中
12 | common-anti-patterns.md | 前 10 个 AI 生成的安全错误,包含 ❌/✅ 代码对、检测启发式方法、OWASP 映射 | 严重
13 | testing-security-code.md | 基于协议的模拟、模拟器与设备差异、CI/CD 密钥链、Swift Testing、突变测试 | 中
14 | compliance-owasp-mapping.md | OWASP Mobile Top 10(2024)、MASVS v2.1.0、MASTG 测试 ID、M1/M3/M9/M10 映射、审计准备 | 中
这些是所有参考文件的主要来源。如有疑问,请优先参考这些来源而非任何二手资料。
以下部分规定了 AI 智能体在使用此技能时应如何行为:范围界定、语气校准、需避免的常见错误、如何选择参考文件以及输出格式要求。
此技能对于 客户端 Apple 平台安全(涵盖 iOS、macOS、tvOS、watchOS 和 visionOS)具有权威性:
SecItemAdd、SecItemCopyMatching、SecItemUpdate、SecItemDelete、查询字典构造、OSStatus 处理、actor/线程隔离、macOS 上的数据保护密钥链(TN3137)kSecClassGenericPassword、kSecClassInternetPassword、kSecClassKey、kSecClassCertificate、kSecClassIdentity、复合主键、自动填充集成kSecAttrAccessible 常量、SecAccessControlCreateWithFlags、数据保护层级、NSFileProtection 对应关系LAContext + 密钥链绑定、布尔门控漏洞、注册变更检测、回退链、evaluatedPolicyDomainStateSecureEnclave.P256 模块、硬件约束(仅限 P256、不可导入、不可导出、非对称)、通过密钥链持久化、模拟器陷阱、iOS 26 后量子(ML-KEM, ML-DSA)SymmetricKey 生命周期、nonce 处理、HKDF、PBKDF2keychain-access-groups 与 com.apple.security.application-groups 授权、扩展、iCloud 密钥链同步SecTrust 评估、SPKI/CA/叶子证书固定、NSPinnedDomains、客户端证书(mTLS)、信任策略属于范围的边缘情况: 用于 mTLS 固定的客户端证书加载(certificate-trust.md)。密钥链中的通行密钥/自动填充凭证存储(keychain-item-classes.md、credential-storage-patterns.md)。将 @AppStorage 标记为不安全存储——重定向到密钥链(common-anti-patterns.md)。
请不要使用此技能回答以下主题。简要解释它们超出范围,并建议去哪里查找。
| 主题 | 排除原因 | 重定向到 |
|---|---|---|
| 应用传输安全(ATS) | 服务器端 TLS 策略,非客户端密钥链 | Apple 的 ATS 文档、Info.plist NSAppTransportSecurity 参考 |
| CloudKit 加密 | 服务器管理的密钥层次结构,非客户端 CryptoKit | CloudKit 文档、CKRecord.encryptedValues |
| 网络安全 / URLSession TLS 配置 | 传输层,非存储层 | Apple URL 加载系统文档;此技能仅涵盖用于 mTLS 的客户端证书加载 |
| 服务器端认证架构 | 后端 JWT 颁发、OAuth 提供商配置 | OWASP ASVS(应用安全验证标准) |
| WebAuthn / 通行密钥服务器端 | 依赖方实现 | Apple "Supporting passkeys" 文档;此技能仅涵盖客户端 ASAuthorizationController 在密钥链中存储凭证的部分 |
| 代码签名 / 配置文件 | 构建/分发,非运行时安全 | Apple 代码签名文档 |
| 越狱检测 | 运行时完整性,非加密存储 | OWASP MASTG MSTG-RESILIENCE 类别 |
SwiftUI @AppStorage | UserDefaults 的包装器——超出范围,除非将其标记为不安全的秘密存储 | common-anti-patterns.md #1 标记了它;没有更深入的覆盖 |
| 跨平台加密(OpenSSL, LibSodium) | 第三方库,非 Apple 框架 | 各自库的文档 |
此技能是非主观且注重正确性的。语气根据严重性进行校准。
默认语气 — 建议性。 对于以下情况使用"考虑"、"建议"、"一种方法是"、"一种常见模式是":架构选择(包装器类设计、actor 与 DispatchQueue)、存在多个有效选项时的算法选择(P256 与 Curve25519、AES-GCM 与 ChaChaPoly)、威胁模型不明确时的可访问性类别选择、测试策略、代码组织。
提升的语气 — 指令性。 仅对上述七条核心指南和 common-anti-patterns.md 中的 10 个反模式使用"始终"、"绝不"、"必须"。这些是安全不变式,而非风格偏好。指令的详尽列表:
OSStatus —— 始终检查 SecItem* 调用的返回码。→ keychain-fundamentals.mdLAContext.evaluatePolicy() 用作独立的认证门控 —— 始终将生物识别与密钥链项目绑定。→ biometric-authentication.mdUserDefaults、Info.plist、.xcconfig 或 NSCoding 归档中。→ credential-storage-patterns.md、common-anti-patterns.md@MainActor 上调用 SecItem* —— 始终使用后台 actor 或队列。→ keychain-fundamentals.mdSecItemAdd 上显式设置 kSecAttrAccessible。→ keychain-access-control.mdSecItemAdd → 在 errSecDuplicateItem 时进行 SecItemUpdate)。→ keychain-fundamentals.mdkSecUseDataProtectionKeychain: true。→ keychain-fundamentals.mdcryptokit-symmetric.md、common-anti-patterns.mdcryptokit-public-key.md、common-anti-patterns.mdInsecure.MD5 或 Insecure.SHA1 用于安全目的。→ cryptokit-symmetric.md、common-anti-patterns.md如果一个模式不在此列表中,请使用建议性语气。不要将警告升级到超出参考文件支持的范围。
拒绝时的语气。 当查询超出范围时,直接但不失礼:"此技能涵盖客户端密钥链和 CryptoKit。对于 ATS 配置,Apple 的 NSAppTransportSecurity 文档是合适的参考资料。" 说明边界,建议替代方案,然后继续。
在最终确定任何输出之前,扫描所有 10 项。每一项都链接到包含正确模式的参考文件。每个条目都特意配对:❌ 错误的生成行为和 ✅ 应使用的纠正模式。
错误 #1 — 生成 LAContext.evaluatePolicy() 作为唯一的生物识别门控。 AI 产生了布尔回调模式,其中 evaluatePolicy 返回 success: Bool,应用根据该布尔值门控访问。该布尔值存在于可挂钩的用户空间内存中——Frida/objection 用一个命令即可绕过。✅ 正确模式: 将秘密存储在带有 .biometryCurrentSet 的 SecAccessControl 后面,通过 SecItemCopyMatching 检索。→ biometric-authentication.md
错误 #2 — 建议使用 SecureEnclave.isAvailable 而没有模拟器防护。 AI 生成了 if SecureEnclave.isAvailable { ... } 而没有 #if !targetEnvironment(simulator)。在模拟器上,isAvailable 返回 false,在所有模拟器测试中静默地采用回退路径。✅ 正确模式: 使用 #if targetEnvironment(simulator) 在编译时抛出/返回明确的错误,仅在设备构建中检查 SecureEnclave.isAvailable。→ secure-enclave.md
错误 #3 — 将外部密钥导入安全隔区。 AI 生成了 SecureEnclave.P256.Signing.PrivateKey(rawRepresentation: someData)。SE 密钥必须在硬件内部生成——SE 类型上没有 init(rawRepresentation:)。init(dataRepresentation:) 仅接受先前创建的 SE 密钥的不透明加密 blob。✅ 正确模式: 在 SE 内部生成,将不透明的 dataRepresentation 持久化到密钥链,通过 init(dataRepresentation:) 恢复。→ secure-enclave.md
错误 #4 — 使用 SecureEnclave.AES 或 SE 进行对称加密。 AI 生成了对不存在的 SE 对称 API 的引用。SE 的内部 AES 引擎不作为开发者 API 公开。在 iOS 26 之前,SE 仅支持 P256 签名和密钥协商。iOS 26 增加了 ML-KEM 和 ML-DSA,而非对称原语。✅ 正确模式: 使用 SE 进行签名/密钥协商;通过 ECDH + HKDF 派生 SymmetricKey 进行加密。→ secure-enclave.md、cryptokit-symmetric.md
错误 #5 — 在 SecItemAdd 中省略 kSecAttrAccessible。 AI 构建了没有可访问性属性的添加字典。系统默认应用 kSecAttrAccessibleWhenUnlocked,这会破坏后台操作,并使安全策略在代码审查中不可见。✅ 正确模式: 始终显式设置 kSecAttrAccessible。→ keychain-access-control.md
错误 #6 — 使用 SecItemAdd 而不处理 errSecDuplicateItem。 AI 仅检查 errSecSuccess,或使用先删除再添加的方式。没有重复项处理,第二次保存会静默失败。先删除再添加会产生竞争窗口并破坏持久引用。✅ 正确模式: 添加或更新模式。→ keychain-fundamentals.md
错误 #7 — 为 AES-GCM 加密指定显式的 nonce。 AI 手动创建 nonce 并将其传递给 AES.GCM.seal。手动 nonce 管理容易导致重用——单次重用就会暴露两个明文的 XOR。当你省略参数时,CryptoKit 会自动生成一个加密随机的 nonce。✅ 正确模式: 调用 AES.GCM.seal(plaintext, using: key) 时不带 nonce: 参数。→ cryptokit-symmetric.md
Philosophy: Non-opinionated, correctness-focused. This skill provides facts, verified patterns, and Apple-documented best practices — not architecture mandates. It covers iOS 13+ as a minimum deployment target, with modern recommendations targeting iOS 17+ and forward-looking guidance through iOS 26 (post-quantum). Every code pattern is grounded in Apple documentation, DTS engineer posts (Quinn "The Eskimo!"), WWDC sessions, and OWASP MASTG — never from memory alone.
What this skill is: A reference for reviewing, improving, and implementing keychain operations, biometric authentication, CryptoKit cryptography, credential lifecycle management, certificate trust, and compliance mapping on Apple platforms.
What this skill is not: A networking guide, a server-side security reference, or an App Transport Security manual. TLS configuration, server certificate management, and backend auth architecture are out of scope except where they directly touch client-side keychain or trust APIs.
Determine the user's intent, then follow the matching branch. If ambiguous, ask.
┌─────────────────────┐
│ What is the task? │
└─────────┬───────────┘
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌─────────┐ ┌───────────┐ ┌────────────┐
│ REVIEW │ │ IMPROVE │ │ IMPLEMENT │
│ │ │ │ │ │
│ Audit │ │ Migrate / │ │ Build from │
│ existing│ │ modernize │ │ scratch │
│ code │ │ existing │ │ │
└────┬────┘ └─────┬─────┘ └─────┬──────┘
│ │ │
▼ ▼ ▼
Run Top-Level Identify gap Identify which
Review Checklist (legacy store? domain(s) apply,
(§ below) against wrong API? load reference
the code. missing auth?) file(s), follow
Flag each item Load migration + ✅ patterns.
as ✅ / ❌ / domain-specific Implement with
⚠️ N/A. reference files. add-or-update,
For each ❌, Follow ✅ patterns, proper error
cite the verify with domain handling, and
reference file checklist. correct access
and specific control from
section. the start.
Goal: Systematically evaluate existing keychain/security code for correctness, security, and compliance.
Procedure:
common-anti-patterns.md. Pay special attention to: UserDefaults for secrets (#1), hardcoded keys (#2), LAContext.evaluatePolicy() as sole auth gate (#3), ignored OSStatus (#4).compliance-owasp-mapping.md categories M1, M3, M9, M10.Key reference files for review:
common-anti-patterns.md (backbone — covers 10 most dangerous patterns)compliance-owasp-mapping.md (if compliance is relevant)Goal: Upgrade existing code from insecure storage, deprecated APIs, or legacy patterns to current best practices.
Procedure:
Identify the migration type:
migration-legacy-stores.md + credential-storage-patterns.mdcryptokit-symmetric.md or cryptokit-public-key.md + migration-legacy-stores.mdcryptokit-public-key.md (RSA migration section)keychain-item-classes.md (migration section)biometric-authentication.mdGoal: Build new keychain/security functionality correctly from the start.
Procedure:
testing-security-code.md — protocol-based abstraction for unit tests, real keychain for integration tests on device.Domain Selection Guide:
| If the task involves… | Load these reference files |
|---|---|
| Storing/reading a password or token | keychain-fundamentals.md + credential-storage-patterns.md |
Choosing which kSecClass to use | keychain-item-classes.md |
| Setting when items are accessible | keychain-access-control.md |
| Face ID / Touch ID gating | biometric-authentication.md + keychain-access-control.md |
These seven rules are non-negotiable. Every keychain/security implementation must satisfy all of them.
1. Never ignoreOSStatus. Every SecItem* call returns an OSStatus. Use an exhaustive switch covering at minimum: errSecSuccess, errSecDuplicateItem (-25299), errSecItemNotFound (-25300), errSecInteractionNotAllowed (-25308). Silently discarding the return value is the root cause of most keychain bugs. → keychain-fundamentals.md
2. Never useLAContext.evaluatePolicy() as a standalone auth gate. This returns a Bool that is trivially patchable at runtime via Frida. Biometric authentication must be keychain-bound: store the secret behind SecAccessControl with .biometryCurrentSet, then let the keychain prompt for Face ID/Touch ID during SecItemCopyMatching. The keychain handles authentication in the Secure Enclave — there is no Bool to patch. → biometric-authentication.md
3. Never store secrets inUserDefaults, Info.plist, .xcconfig, or NSCoding archives. These produce plaintext artifacts readable from unencrypted backups. The Keychain is the only Apple-sanctioned store for credentials. → credential-storage-patterns.md, common-anti-patterns.md
4. Never callSecItem* on @MainActor. Every keychain call is an IPC round-trip to securityd that blocks the calling thread. Use a dedicated actor (iOS 17+) or serial DispatchQueue (iOS 13–16) for all keychain access. → keychain-fundamentals.md
5. Always setkSecAttrAccessible explicitly. The system default (kSecAttrAccessibleWhenUnlocked) breaks all background operations and may not match your threat model. Choose the most restrictive class that satisfies your access pattern. For background tasks: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. For highest sensitivity: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. → keychain-access-control.md
6. Always use the add-or-update pattern. SecItemAdd followed by SecItemUpdate on errSecDuplicateItem. Never delete-then-add (creates a race window and destroys persistent references). Never call SecItemAdd without handling the duplicate case. → keychain-fundamentals.md
7. Always target the data protection keychain on macOS. Set kSecUseDataProtectionKeychain: true for every SecItem* call on macOS targets. Without it, queries silently route to the legacy file-based keychain which has different behavior, ignores unsupported attributes, and cannot use biometric protection or Secure Enclave keys. Mac Catalyst and iOS-on-Mac do this automatically. → keychain-fundamentals.md
| Constant | When Decryptable | Survives Backup | Survives Device Migration | Background Safe | Use When |
|---|---|---|---|---|---|
WhenPasscodeSetThisDeviceOnly | Unlocked + passcode set | ❌ | ❌ | ❌ | Highest-security secrets; removed if passcode removed |
WhenUnlockedThisDeviceOnly | Unlocked | ❌ | ❌ | ❌ | Device-bound secrets not needed in background |
WhenUnlocked | Unlocked | ✅ | ✅ |
Deprecated (never use): kSecAttrAccessibleAlways, kSecAttrAccessibleAlwaysThisDeviceOnly — deprecated iOS 12.
Rule of thumb: Need background access (push handlers, background refresh)? Start with AfterFirstUnlockThisDeviceOnly. Foreground-only? Start with WhenUnlockedThisDeviceOnly. Tighten to WhenPasscodeSetThisDeviceOnly for high-value secrets. Use non-ThisDeviceOnly variants only when iCloud sync or backup migration is required.
| Need | Algorithm | Min iOS | Notes |
|---|---|---|---|
| Hash data | SHA256 / SHA384 / SHA512 | 13 | SHA3_256/SHA3_512 available iOS 18+ |
| Authenticate data (MAC) | HMAC<SHA256> | 13 | Always verify with constant-time comparison (built-in) |
| Encrypt data (authenticated) | AES.GCM |
When reviewing code, search for these patterns. Any match is a finding. ❌ = insecure pattern signature to detect in user code. ✅ = apply the corrective pattern in the referenced file.
| Search For | Anti-Pattern | Severity | Reference |
|---|---|---|---|
UserDefaults.standard.set + token/key/secret/password | Plaintext credential storage | CRITICAL | common-anti-patterns.md #1 |
| Hardcoded base64/hex strings (≥16 chars) in source | Hardcoded cryptographic key | CRITICAL | common-anti-patterns.md #2 |
evaluatePolicy without SecItemCopyMatching nearby | LAContext-only biometric gate | CRITICAL |
Use this checklist for a rapid sweep across all 14 domains. Each item maps to one or more reference files for deep-dive investigation. For domain-specific deep checks, use the Summary Checklist at the bottom of each reference file.
1. Secrets are in Keychain, not UserDefaults/plist/source — No credentials, tokens, or cryptographic keys in UserDefaults, Info.plist, .xcconfig, hardcoded strings, or NSCoding archives. OWASP M9 (Insecure Data Storage) directly violated. → common-anti-patterns.md #1–2, credential-storage-patterns.md, migration-legacy-stores.md, compliance-owasp-mapping.md
2. EveryOSStatus is checked — All calls handle return codes with exhaustive or equivalent. No ignored returns. is handled non-destructively (retry later, never delete). → , #4
---|---|---|---
1 | keychain-fundamentals.md | SecItem* CRUD, query dictionaries, OSStatus handling, actor-based wrappers, macOS TN3137 routing | CRITICAL
2 | keychain-item-classes.md | Five kSecClass types, composite primary keys, GenericPassword vs InternetPassword, ApplicationTag vs ApplicationLabel | HIGH
3 | keychain-access-control.md | Seven accessibility constants, SecAccessControl flags, data protection tiers, NSFileProtection sidebar | CRITICAL
4 | biometric-authentication.md | Keychain-bound biometrics, LAContext bypass vulnerability, enrollment change detection, fallback chains | CRITICAL
5 | secure-enclave.md | Hardware-backed P256 keys, CryptoKit SecureEnclave module, persistence, simulator traps, iOS 26 post-quantum | HIGH
6 | cryptokit-symmetric.md | SHA-2/3 hashing, HMAC, AES-GCM/ChaChaPoly encryption, SymmetricKey management, nonce handling, HKDF/PBKDF2 | HIGH
7 | cryptokit-public-key.md | ECDSA signing, ECDH key agreement, HPKE (iOS 17+), ML-KEM/ML-DSA post-quantum (iOS 26+), curve selection | HIGH
8 | credential-storage-patterns.md | OAuth2/OIDC token lifecycle, API key storage, refresh token rotation, runtime secrets, logout cleanup | CRITICAL
9 | | Access groups, Team ID prefixes, app extensions, Keychain Sharing vs App Groups entitlements, iCloud sync | MEDIUM
10 | | SecTrust evaluation, SPKI/CA/leaf pinning, NSPinnedDomains, client certificates (mTLS), trust policies | HIGH
11 | | UserDefaults/plist/NSCoding → Keychain migration, secure deletion, first-launch cleanup, versioned migration | MEDIUM
12 | | Top 10 AI-generated security mistakes with ❌/✅ code pairs, detection heuristics, OWASP mapping | CRITICAL
13 | | Protocol-based mocking, simulator vs device differences, CI/CD keychain, Swift Testing, mutation testing | MEDIUM
14 | | OWASP Mobile Top 10 (2024), MASVS v2.1.0, MASTG test IDs, M1/M3/M9/M10 mapping, audit readiness | MEDIUM
These are the primary sources underpinning all reference files. When in doubt, defer to these over any secondary source.
The sections below govern how an AI agent should behave when using this skill: what's in scope, what's out, tone calibration, common mistakes to avoid, how to select reference files, and output formatting requirements.
This skill is authoritative for client-side Apple platform security across iOS, macOS, tvOS, watchOS, and visionOS:
SecItemAdd, SecItemCopyMatching, SecItemUpdate, SecItemDelete, query dictionary construction, OSStatus handling, actor/thread isolation, the data protection keychain on macOS (TN3137)kSecClassGenericPassword, kSecClassInternetPassword, kSecClassKey, kSecClassCertificate, kSecClassIdentity, composite primary keys, AutoFill integrationEdge cases that ARE in scope: Client-side certificate loading for mTLS pinning (certificate-trust.md). Passkey/AutoFill credential storage in Keychain (keychain-item-classes.md, credential-storage-patterns.md). @AppStorage flagged as insecure storage — redirect to Keychain (common-anti-patterns.md).
Do not answer the following topics using this skill. Briefly explain they are out of scope and suggest where to look.
| Topic | Why excluded | Redirect to |
|---|---|---|
| App Transport Security (ATS) | Server-side TLS policy, not client keychain | Apple's ATS documentation, Info.plist NSAppTransportSecurity reference |
| CloudKit encryption | Server-managed key hierarchy, not client CryptoKit | CloudKit documentation, CKRecord.encryptedValues |
| Network security / URLSession TLS config | Transport layer, not storage layer | Apple URL Loading System docs; this skill covers only client certificate loading for mTLS |
| Server-side auth architecture | Backend JWT issuance, OAuth provider config | OWASP ASVS (Application Security Verification Standard) |
| WebAuthn / passkeys server-side | Relying party implementation | Apple "Supporting passkeys" documentation; this skill covers client-side only where it stores credentials in Keychain |
This skill is non-opinionated and correctness-focused. Tone calibrates based on severity.
Default tone — advisory. Use "consider," "suggest," "one approach is," "a common pattern is" for: architecture choices (wrapper class design, actor vs DispatchQueue), algorithm selection when multiple valid options exist (P256 vs Curve25519, AES-GCM vs ChaChaPoly), accessibility class selection when the threat model is unclear, testing strategy, code organization.
Elevated tone — directive. Use "always," "never," "must" only for the seven Core Guidelines above and the 10 anti-patterns in common-anti-patterns.md. These are security invariants, not style preferences. The exhaustive list of directives:
OSStatus — always check return codes from SecItem* calls. → keychain-fundamentals.mdLAContext.evaluatePolicy() as a standalone auth gate — always bind biometrics to keychain items. → biometric-authentication.mdUserDefaults, Info.plist, .xcconfig, or NSCoding archives. → credential-storage-patterns.md, If a pattern is not on this list, use advisory tone. Do not escalate warnings beyond what the reference files support.
Tone when declining. When a query falls outside scope, be direct but not dismissive: "This skill covers client-side keychain and CryptoKit. For ATS configuration, Apple's NSAppTransportSecurity documentation is the right reference." State the boundary, suggest an alternative, move on.
Before finalizing any output, scan for all 10. Each links to the reference file containing the correct pattern. Each entry is intentionally paired: ❌ incorrect generated behavior and ✅ corrective pattern to use instead.
Mistake #1 — GeneratingLAContext.evaluatePolicy() as the sole biometric gate. AI produces the boolean-callback pattern where evaluatePolicy returns success: Bool and the app gates access on that boolean. The boolean exists in hookable user-space memory — Frida/objection bypass it with one command. ✅ Correct pattern: Store a secret behind SecAccessControl with .biometryCurrentSet, retrieve via SecItemCopyMatching. → biometric-authentication.md
Mistake #2 — SuggestingSecureEnclave.isAvailable without simulator guard. AI generates if SecureEnclave.isAvailable { ... } without #if !targetEnvironment(simulator). On simulators, isAvailable returns false, silently taking the fallback path in all simulator testing. ✅ Correct pattern: Use #if targetEnvironment(simulator) to throw/return a clear error at compile time, check SecureEnclave.isAvailable only in device builds. → secure-enclave.md
Mistake #3 — Importing external keys into the Secure Enclave. AI generates SecureEnclave.P256.Signing.PrivateKey(rawRepresentation: someData). SE keys must be generated inside the hardware — there is no init(rawRepresentation:) on SE types. init(dataRepresentation:) accepts only the opaque encrypted blob from a previously created SE key. ✅ Correct pattern: Generate inside SE, persist opaque dataRepresentation to keychain, restore via init(dataRepresentation:). → secure-enclave.md
Mistake #4 — UsingSecureEnclave.AES or SE for symmetric encryption. AI generates references to non-existent SE symmetric APIs. The SE's internal AES engine is not exposed as a developer API. Pre-iOS 26, the SE supports only P256 signing and key agreement. iOS 26 adds ML-KEM and ML-DSA, not symmetric primitives. ✅ Correct pattern: Use SE for signing/key agreement; derive a SymmetricKey via ECDH + HKDF for encryption. → secure-enclave.md, cryptokit-symmetric.md
Mistake #5 — OmittingkSecAttrAccessible in SecItemAdd. AI builds add dictionaries without an accessibility attribute. The system applies kSecAttrAccessibleWhenUnlocked by default, which breaks background operations and makes security policy invisible in code review. ✅ Correct pattern: Always set kSecAttrAccessible explicitly. → keychain-access-control.md
Mistake #6 — UsingSecItemAdd without handling errSecDuplicateItem. AI checks only for errSecSuccess, or uses delete-then-add. Without duplicate handling, the second save silently fails. Delete-then-add creates a race window and destroys persistent references. ✅ Correct pattern: Add-or-update pattern. → keychain-fundamentals.md
Mistake #7 — Specifying explicit nonces for AES-GCM encryption. AI creates a nonce manually and passes it to AES.GCM.seal. Manual nonce management invites reuse — a single reuse reveals the XOR of both plaintexts. CryptoKit generates a cryptographically random nonce automatically when you omit the parameter. ✅ Correct pattern: Call AES.GCM.seal(plaintext, using: key) without a nonce: parameter. → cryptokit-symmetric.md, common-anti-patterns.md #6
Mistake #8 — Using raw ECDH shared secret as a symmetric key. AI takes the output of sharedSecretFromKeyAgreement and uses it directly via withUnsafeBytes. Raw shared secrets have non-uniform distribution. CryptoKit's SharedSecret deliberately has no withUnsafeBytes — this code requires an unsafe workaround, which is a clear signal of misuse. ✅ Correct pattern: Always derive via sharedSecret.hkdfDerivedSymmetricKey(...). → cryptokit-public-key.md, common-anti-patterns.md #7
Mistake #9 — Claiming SHA-3 requires iOS 26. AI conflates the post-quantum WWDC 2025 additions with the SHA-3 additions from 2024. SHA-3 family types were added in iOS 18 / macOS 15. iOS 26 introduced ML-KEM and ML-DSA, not SHA-3. ✅ Correct version tags: SHA-3 → iOS 18+. ML-KEM/ML-DSA → iOS 26+. → cryptokit-symmetric.md
Mistake #10 — Missing first-launch keychain cleanup. AI generates a standard @main struct MyApp: App without keychain cleanup. Keychain items survive app uninstallation. A reinstalled app inherits stale tokens, expired keys, and orphaned credentials. ✅ Correct pattern: Check a UserDefaults flag, SecItemDelete across all five kSecClass types on first launch. → common-anti-patterns.md #9, migration-legacy-stores.md
Load the minimum set of files needed to answer the query. Do not load all 14 — they total ~7,000+ lines and will dilute focus.
| Query type | Load these files | Reason |
|---|---|---|
| "Review my keychain code" | common-anti-patterns.md → then domain-specific files based on what the code does | Anti-patterns file is the review backbone |
| "Is this biometric auth secure?" | biometric-authentication.md + common-anti-patterns.md (#3) | Boolean gate is the #1 biometric risk |
| "Store a token / password" | keychain-fundamentals.md + credential-storage-patterns.md | CRUD + lifecycle |
| "Encrypt / hash data" |
Loading order: (1) Most specific file for the query. (2) Add common-anti-patterns.md for any review/audit. (3) Add keychain-fundamentals.md for any SecItem* task. (4) Add compliance-owasp-mapping.md only if OWASP/audit is mentioned. (5) Never load files speculatively.
1. Always include ✅/❌ code examples. Show both the incorrect/insecure version and the correct/secure version. Exception: pure informational queries ("what accessibility constants exist?") do not need ❌ examples.
2. Always cite iOS version requirements. Every API recommendation must include the minimum iOS version inline: "Use HPKE (iOS 17+) for hybrid public-key encryption."
3. Always cite the reference file. When referencing a pattern or anti-pattern, name the source: "See biometric-authentication.md for the full keychain-bound pattern."
4. Always includeOSStatus handling in keychain code. Never output bare SecItemAdd / SecItemCopyMatching calls without error handling. At minimum: errSecSuccess, errSecDuplicateItem (for add), errSecItemNotFound (for read), errSecInteractionNotAllowed (non-destructive retry).
5. Always specifykSecAttrAccessible in add examples. Every SecItemAdd code example must include an explicit accessibility constant.
6. State severity for findings. CRITICAL = exploitable vulnerability. HIGH = silent data loss or wrong security boundary. MEDIUM = suboptimal but not immediately exploitable.
7. Prefer modern APIs with fallback notes. Default to iOS 17+ (actor-based). Note fallbacks: iOS 15–16 (serial DispatchQueue + async/await bridge), iOS 13–14 (completion handlers).
8. Never fabricate citations or WWDC session numbers. If a session/reference is not in the loaded references, say it is unverified and avoid inventing identifiers.
9. Implementation and improvement responses must conclude with a## Reference Files section. List every reference file that informed the response with a one-line note on what it contributed. This applies to all response types — code generation, migration guides, and improvements — not just reviews. Example: - \keychain-fundamentals.md — SecItem CRUD and error handling.
10. Cite SKILL.md structural sections when they govern the response. When declining an out-of-scope query, reference "Scope Boundaries — Exclusions." When using advisory vs directive tone on an opinion-seeking question, reference "Tone Rules." When a version constraint shapes the answer, reference "Version Baseline Quick Reference." A brief parenthetical is sufficient — e.g., "(per Scope Boundaries — Exclusions)."
Things the agent must do:
Things the agent must not do:
SecItemAdd without errSecDuplicateItem fallback. Never show SecItemCopyMatching without errSecItemNotFound handling.| API / Feature | Minimum iOS | Common AI mistake |
|---|---|---|
| CryptoKit (SHA-2, AES-GCM, P256, ECDH) | 13 | Claiming iOS 15+ |
SecureEnclave.P256 (CryptoKit) | 13 | Claiming iOS 15+ |
SHA-3 (SHA3_256, SHA3_384, SHA3_512) | 18 | Claiming iOS 26+ |
HPKE (HPKE.Sender, HPKE.Recipient) |
Run before finalizing any response that includes security code:
SecItemAdd has an explicit kSecAttrAccessible valueSecItemAdd handles errSecDuplicateItem with SecItemUpdate fallbackSecItemCopyMatching handles errSecItemNotFoundLAContext.evaluatePolicy() used as standalone auth gateSecItem* calls on @MainActor or main threadWeekly Installs
84
Repository
GitHub Stars
2
First Seen
Mar 6, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode82
cline81
codex81
gemini-cli81
kimi-cli81
cursor81
Azure PostgreSQL 无密码身份验证配置指南:Entra ID 迁移与访问管理
34,800 周安装
代码审查员工具包 - 自动化PR分析、代码质量检查与审查报告生成
512 周安装
Salesforce Apex 代码生成与审查工具 - sf-apex 技能详解
535 周安装
HeroUI v2 到 v3 迁移指南:破坏性变更、复合组件、Tailwind v4 升级
533 周安装
draw.io 图表技能:XML 编辑、PNG 转换与专业设计指南
514 周安装
Excel-CLI 命令行工具:Windows Excel 自动化脚本与批处理操作指南
515 周安装
Apollo GraphQL Skill 创建指南 - 为AI智能体构建技能规范与最佳实践
521 周安装
keychain-fundamentals.md (TN3137 section)keychain-sharing.mdcertificate-trust.mdFollow the migration pattern in the relevant reference file. Every migration section includes: pre-migration validation, atomic migration step, legacy data secure deletion, post-migration verification.
Run the domain-specific checklist from the reference file after migration completes.
Verify no regressions using guidance from testing-security-code.md.
| Hardware-backed keys | secure-enclave.md |
| Encrypting / hashing data | cryptokit-symmetric.md |
| Signing / key exchange / HPKE | cryptokit-public-key.md |
| OAuth tokens / API keys / logout | credential-storage-patterns.md |
| Sharing between app and extension | keychain-sharing.md |
| TLS pinning / client certificates | certificate-trust.md |
| Replacing UserDefaults / plist secrets | migration-legacy-stores.md |
| Writing tests for security code | testing-security-code.md |
| Enterprise audit / OWASP compliance | compliance-owasp-mapping.md |
| ❌ |
| Syncable secrets (system default — avoid implicit use) |
AfterFirstUnlockThisDeviceOnly | After first unlock → restart | ❌ | ❌ | ✅ | Background tasks, push handlers, device-bound |
AfterFirstUnlock | After first unlock → restart | ✅ | ✅ | ✅ | Background tasks that must survive restore |
| 13 |
| 256-bit key, 96-bit nonce, 128-bit tag. Never reuse nonce with same key |
| Encrypt data (mobile-optimized) | ChaChaPoly | 13 | Better on devices without AES-NI (older Apple Watch) |
| Sign data | P256.Signing / Curve25519.Signing | 13 | Use P256 for interop, Curve25519 for performance |
| Key agreement | P256.KeyAgreement / Curve25519.KeyAgreement | 13 | Always derive symmetric key via HKDF — never use raw shared secret |
| Hybrid public-key encryption | HPKE | 17 | Replaces manual ECDH+HKDF+AES-GCM chains |
| Hardware-backed signing | SecureEnclave.P256.Signing | 13 | P256 only; key never leaves hardware |
| Post-quantum key exchange | MLKEM768 | 26 | Formal verification (ML-KEM FIPS 203) |
| Post-quantum signing | MLDSA65 | 26 | Formal verification (ML-DSA FIPS 204) |
| Password → key derivation | PBKDF2 (via CommonCrypto) | 13 | ≥600,000 iterations SHA-256 (OWASP 2024) |
| Key → key derivation | HKDF<SHA256> | 13 | Extract-then-expand; always use info parameter for domain separation |
common-anti-patterns.md #3 |
SecItemAdd without checking return / OSStatus | Ignored error code | HIGH | common-anti-patterns.md #4 |
No kSecAttrAccessible in add dictionary | Implicit accessibility class | HIGH | common-anti-patterns.md #5 |
AES.GCM.Nonce() inside a loop with same key | Potential nonce reuse | CRITICAL | common-anti-patterns.md #6 |
sharedSecret.withUnsafeBytes without HKDF | Raw shared secret as key | HIGH | common-anti-patterns.md #7 |
kSecAttrAccessibleAlways | Deprecated accessibility | HIGH | keychain-access-control.md |
SecureEnclave.isAvailable without #if !targetEnvironment(simulator) | Simulator false-negative trap | MEDIUM | secure-enclave.md |
kSecAttrSynchronizable: true + ThisDeviceOnly | Contradictory constraints | MEDIUM | keychain-item-classes.md |
SecTrustEvaluate (sync, deprecated) | Legacy trust evaluation | MEDIUM | certificate-trust.md |
kSecClassGenericPassword + kSecAttrServer | Wrong class for web credentials | MEDIUM | keychain-item-classes.md |
SecItem*switcherrSecInteractionNotAllowedkeychain-fundamentals.mdcommon-anti-patterns.md3. Biometric auth is keychain-bound — If biometrics are used, authentication is enforced via SecAccessControl + keychain access, not LAContext.evaluatePolicy() alone. → biometric-authentication.md, common-anti-patterns.md #3
4. Accessibility classes are explicit and correct — Every keychain item has an explicit kSecAttrAccessible value matching its access pattern (background vs foreground, device-bound vs syncable). No deprecated Always constants. → keychain-access-control.md
5. NoSecItem* calls on @MainActor — All keychain operations run on a dedicated actor or background queue. No synchronous keychain access in UI code, viewDidLoad, or application(_:didFinishLaunchingWithOptions:). → keychain-fundamentals.md
6. CorrectkSecClass for each item type — Web credentials use InternetPassword (not GenericPassword) for AutoFill. Cryptographic keys use kSecClassKey with proper kSecAttrKeyType. App secrets use GenericPassword with kSecAttrService + kSecAttrAccount. → keychain-item-classes.md
7. CryptoKit used correctly — Nonces never reused with the same key. ECDH shared secrets always derived through HKDF before use as symmetric keys. SymmetricKey material stored in Keychain, not in memory or files. Crypto operations covered by protocol-based unit tests. → cryptokit-symmetric.md, cryptokit-public-key.md, testing-security-code.md
8. Secure Enclave constraints respected — SE keys are P256 only (classical), never imported (always generated on-device), device-bound (no backup/sync). Availability checks guard against simulator and keychain-access-groups entitlement issues. → secure-enclave.md
9. Sharing and access groups configured correctly — kSecAttrAccessGroup uses full TEAMID.group.identifier format. Entitlements match between app and extensions. No accidental cross-app data exposure. → keychain-sharing.md
10. Certificate trust evaluation is current — Uses SecTrustEvaluateAsyncWithError (not deprecated synchronous SecTrustEvaluate). Pinning strategy uses SPKI hash or NSPinnedDomains (not leaf certificate pinning which breaks on annual rotation). → certificate-trust.md
11. macOS targets data protection keychain — All macOS SecItem* calls include kSecUseDataProtectionKeychain: true (except Mac Catalyst / iOS-on-Mac where it's automatic). → keychain-fundamentals.md
keychain-sharing.mdcertificate-trust.mdmigration-legacy-stores.mdcommon-anti-patterns.mdtesting-security-code.mdcompliance-owasp-mapping.mdkSecAttrAccessible constants, SecAccessControlCreateWithFlags, data protection tiers, NSFileProtection correspondenceLAContext + keychain binding, the boolean gate vulnerability, enrollment change detection, fallback chains, evaluatedPolicyDomainStateSecureEnclave.P256 module, hardware constraints (P256-only, no import, no export, no symmetric), persistence via keychain, simulator traps, iOS 26 post-quantum (ML-KEM, ML-DSA)SymmetricKey lifecycle, nonce handling, HKDF, PBKDF2keychain-access-groups vs com.apple.security.application-groups entitlements, extensions, iCloud Keychain syncSecTrust evaluation, SPKI/CA/leaf pinning, NSPinnedDomains, client certificates (mTLS), trust policiesASAuthorizationController| Code signing / provisioning profiles | Build/distribution, not runtime security | Apple code signing documentation |
| Jailbreak detection | Runtime integrity, not cryptographic storage | OWASP MASTG MSTG-RESILIENCE category |
SwiftUI@AppStorage | Wrapper over UserDefaults — out of scope except to flag it as insecure for secrets | common-anti-patterns.md #1 flags it; no deeper coverage |
| Cross-platform crypto (OpenSSL, LibSodium) | Third-party libraries, not Apple frameworks | Respective library documentation |
common-anti-patterns.mdSecItem* on @MainActor — always use a background actor or queue. → keychain-fundamentals.mdkSecAttrAccessible explicitly on every SecItemAdd. → keychain-access-control.mdSecItemAdd → SecItemUpdate on errSecDuplicateItem). → keychain-fundamentals.mdkSecUseDataProtectionKeychain: true on macOS targets. → keychain-fundamentals.mdcryptokit-symmetric.md, common-anti-patterns.mdcryptokit-public-key.md, common-anti-patterns.mdInsecure.MD5 or Insecure.SHA1 for security purposes. → cryptokit-symmetric.md, common-anti-patterns.mdcryptokit-symmetric.md| Symmetric operations |
| "Sign data / key exchange" | cryptokit-public-key.md | Asymmetric operations |
| "Use Secure Enclave" | secure-enclave.md + keychain-fundamentals.md | SE keys need keychain persistence |
| "Share keychain with extension" | keychain-sharing.md + keychain-fundamentals.md | Access groups + CRUD |
| "Migrate from UserDefaults" | migration-legacy-stores.md + credential-storage-patterns.md | Migration + target patterns |
| "TLS pinning / mTLS" | certificate-trust.md | Trust evaluation |
| "Which kSecClass?" | keychain-item-classes.md | Class selection + primary keys |
| "Set up data protection" | keychain-access-control.md | Accessibility constants |
| "Write tests for keychain code" | testing-security-code.md | Protocol mocks + CI/CD |
| "OWASP compliance audit" | compliance-owasp-mapping.md + common-anti-patterns.md | Mapping + detection |
| "Full security review" | common-anti-patterns.md + all files touched by the code | Start with anti-patterns, expand |
| 17 |
| Claiming iOS 15+ or iOS 18+ |
| ML-KEM / ML-DSA (post-quantum) | 26 | Conflating with SHA-3 |
SecAccessControl with .biometryCurrentSet | 11.3 | Claiming iOS 13+ |
kSecUseDataProtectionKeychain (macOS) | macOS 10.15 | Omitting entirely on macOS |
Swift concurrency actor | 13 (runtime), 17+ (recommended) | Claiming iOS 15 minimum |
LAContext.evaluatedPolicyDomainState | 9 | Not knowing it exists |
NSPinnedDomains (declarative pinning) | 14 | Claiming iOS 16+ |
kSecUseDataProtectionKeychain: true#if targetEnvironment(simulator) guardAES.GCM.seal unless the user has a documented reason