iOS如何检测根证书已安装且被用户手动信任?
检测iOS用户是否手动信任根CA证书
我完全理解你的困扰——SecTrustEvaluate的返回结果在不同iOS版本里表现不一致,而且没法区分是系统默认信任还是用户手动在「通用->关于本机->信任设置」里确认的状态。这里有几个经过验证的可行方案,帮你精准检测用户的手动信任操作:
方案1:查询证书的kSecAttrIsUserTrusted属性
这个系统属性会明确标记证书是否是用户手动在设置中确认信任的,不受iOS版本差异影响。你可以通过SecItemCopyMatching查询已安装证书的该属性:
BOOL isUserManuallyTrusted(SecCertificateRef cert) { BOOL result = NO; NSDictionary *query = @{ (__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassCertificate, (__bridge NSString *)kSecValueRef: (__bridge id)cert, (__bridge NSString *)kSecReturnAttributes: @YES }; CFDictionaryRef attributes = NULL; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&attributes); if (status == errSecSuccess) { NSNumber *isUserTrusted = (__bridge NSNumber *)CFDictionaryGetValue(attributes, kSecAttrIsUserTrusted); result = [isUserTrusted boolValue]; CFRelease(attributes); } return result; }
方案2:结合SecTrustEvaluateWithError做完整验证
在iOS 12及以上,推荐使用更现代的SecTrustEvaluateWithError API,同时搭配上面的属性检查,确保信任链中确实包含用户手动信任的根CA:
BOOL checkManualUserTrust(SecCertificateRef fullChain) { SecPolicyRef policy = SecPolicyCreateBasicX509(); SecTrustRef trust = NULL; OSStatus status = SecTrustCreateWithCertificates(fullChain, policy, &trust); if (status != errSecSuccess) { CFRelease(policy); return NO; } NSError *error = nil; BOOL trustResult = SecTrustEvaluateWithError(trust, &error); BOOL isManualTrust = NO; if (trustResult) { // 遍历信任链,检查是否存在用户手动信任的证书 CFIndex certCount = SecTrustGetCertificateCount(trust); for (CFIndex i = 0; i < certCount; i++) { SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i); if (isUserManuallyTrusted(cert)) { isManualTrust = YES; break; } } } CFRelease(trust); CFRelease(policy); return isManualTrust; }
关键注意事项
kSecAttrIsUserTrusted仅对用户手动安装的配置文件中的根CA生效,系统预装的根证书不会带有这个标记。- 测试时要注意:安装配置文件后未手动信任,该属性为
NO;用户手动信任后变为YES;卸载配置文件后该标记会被清除。 - iOS 10及以上系统无需额外权限即可查询该属性,但确保你的应用代码中已正确导入Security框架。
内容的提问来源于stack exchange,提问作者Al Ga




