如何合规处理WKWebView中自签名证书的身份验证挑战?
合规处理WKWebView自签名证书验证的方案
嘿,我之前也踩过这个坑——直接绕过所有证书验证肯定过不了App Store审核,因为苹果认为这会引入严重的安全风险(比如中间人攻击)。下面给你几个合规的解决思路,都是苹果认可的方式:
1. 仅在Debug环境下绕过验证(适合开发调试)
如果你的自签名服务器只是开发阶段用,那可以只在Debug模式下开启绕过,Release版本严格走正常验证流程。这样既不影响开发,又能满足审核要求:
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { #ifdef DEBUG if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); return; } #endif // Release版本走默认处理 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); }
2. 嵌入自签名证书并校验(生产环境合规方案)
这是苹果推荐的合规做法:把你的自签名证书打包进App,在验证时对比服务器返回的证书和本地嵌入的证书,只有匹配时才信任,避免盲目绕过。
步骤:
- 把你的自签名证书(.cer或.pem格式)添加到Xcode项目中,确保它被包含在App的target里。
- 在
didReceiveAuthenticationChallenge委托方法中,加载本地证书,然后校验服务器证书的合法性:
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; // 加载本地嵌入的证书 NSString *certPath = [[NSBundle mainBundle] pathForResource:@"YourSelfSignedCert" ofType:@"cer"]; NSData *certData = [NSData dataWithContentsOfFile:certPath]; SecCertificateRef localCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); // 将本地证书加入信任链 NSArray *certArray = @[(__bridge id)localCert]; SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)certArray); SecTrustSetAnchorCertificatesOnly(serverTrust, true); // 执行验证 SecTrustResultType trustResult; SecTrustEvaluate(serverTrust, &trustResult); if (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed) { NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } else { // 验证不通过,拒绝连接 completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } CFRelease(localCert); return; } // 其他类型的验证走默认处理 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); }
额外优化:校验证书指纹
为了更安全,你还可以预先计算自签名证书的SHA256指纹,在验证时对比服务器证书的指纹是否一致,避免证书被篡改:
// 获取证书的SHA256指纹 - (NSString *)sha256FingerprintForCert:(SecCertificateRef)cert { NSData *certData = (__bridge NSData *)SecCertificateCopyData(cert); uint8_t digest[CC_SHA256_DIGEST_LENGTH]; CC_SHA256(certData.bytes, (CC_LONG)certData.length, digest); NSMutableString *fingerprint = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { [fingerprint appendFormat:@"%02x", digest[i]]; } return [fingerprint uppercaseString]; }
然后在验证时,对比这个指纹和你预先保存的指纹字符串即可。
为什么你的原代码过不了审核?
苹果的审核指南明确禁止盲目绕过所有服务器证书验证的做法,因为这会让App用户暴露在中间人攻击的风险中——任何恶意服务器都能被你的App信任,这严重违反了安全要求。而上面的方案要么只在Debug模式下临时绕过,要么只信任你指定的合法证书,都是符合苹果安全规范的。
内容的提问来源于stack exchange,提问作者jailani
相关产品推荐
相关产品推荐

