didReceiveAuthenticationChallenge多次调用及NSURLErrorDomainCode=-999问题咨询
问题描述
在基于React-Native-Webview开发的应用中,为网站实现SSL固定校验,通过didReceiveAuthenticationChallenge方法处理认证挑战时遇到以下异常:
- 该方法被调用3次
- 前两次调用能获取到相同的服务器证书,第三次调用时
SecTrustGetCertificateAtIndex(serverTrust, 0)返回nil - 最终出现
NSURLErrorDomainCode=-999错误
相关代码片段:
- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0); // 后续校验逻辑... }
服务器仅安装了用于比对的单张证书,疑问:此行为是否属于方法的正常表现?
解答
这种三次调用+第三次证书为空+返回-999错误的情况不属于正常行为,核心原因和解决方向如下:
NSURLErrorDomainCode=-999的本质
这个错误表示请求被主动取消,通常是前两次认证处理逻辑存在缺陷,导致Webview终止了后续请求流程。比如未正确调用completionHandler、错误地拒绝了合法认证等,都会触发该错误。第三次调用时证书为空的可能原因
- 认证挑战类型变更:前两次是服务器证书认证(
NSURLAuthenticationMethodServerTrust),但第三次可能是其他类型的认证(比如客户端证书认证、HTTP Basic认证等),此时challenge.protectionSpace.serverTrust会为nil,自然无法获取到证书。 - Webview的子请求触发:Webview加载页面时可能发起多个子请求(如静态资源、第三方脚本等),若某个子请求并非HTTPS协议,或者服务器返回的信任链异常,就会出现
serverTrust无效的情况。 - 代码未做空值校验:当前代码直接获取
serverTrust和证书,未判断serverTrust是否为nil,当serverTrust无效时,SecTrustGetCertificateAtIndex必然返回nil。
- 修复建议
- 先校验认证类型:在处理挑战前,先判断是否为服务器证书认证,非目标类型直接走默认处理:
if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); return; } - 增加空值判断:确保
serverTrust有效后再获取证书:SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; if (!serverTrust || SecTrustGetCertificateCount(serverTrust) == 0) { completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); return; } SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0); - 正确完成认证流程:证书校验通过后,必须调用
completionHandler返回合法凭证;校验失败则明确拒绝,避免Webview因等待处理超时取消请求:// 假设校验通过 if (证书校验逻辑通过) { NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } else { completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil); } - 排查第三次请求来源:通过
challenge.protectionSpace.host查看第三次请求的目标地址,确认是否为预期内的HTTPS请求,排查是否存在非预期的子请求或重定向问题。
内容的提问来源于stack exchange,提问作者SmalliSax
相关产品推荐
相关产品推荐

