SSL Pinning和AFNetworking 2.5.0存在问题(NSURLErrorDomain错误-1012)

34
我们一直在使用 AFNetworking 2.5.0,但使用 SSL 来保护应用的网络连接一直是个大问题。我们使用的是自签名证书,并且采用了固定证书的自定义安全策略。虽然我们已经测试了很多由 AFNetworking 提供的配置,但到目前为止还没有找到解决方法。我们收到的错误消息如下:
“2015-01-05 19:03:07.191 AppName[9301:319051] Error updating user journey. Error: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x7ae056b0 {NSErrorFailingURLKey=https://api.XXX.com/XXX/XXX/, NSErrorFailingURLStringKey=https://api.XXX.com/XXX/XXX/}”
我们的证书在其他客户端上(例如 cURL 和 Android)运行良好。使用 HTTP 时,我们的实现也能正常工作。请问是否有关于固定证书和 AFNetworking 的问题?如果有,我们将非常感谢您的帮助。
以下是部分代码实现:
+ (AFSecurityPolicy*)customSecurityPolicy {
   AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
   NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"filename" ofType:@"der"];
   NSData *certData = [NSData dataWithContentsOfFile:cerPath];
   [securityPolicy setAllowInvalidCertificates:NO];
   [securityPolicy setValidatesCertificateChain:NO];
   [securityPolicy setPinnedCertificates:@[certData]];
   return securityPolicy;
}

+ (AFHTTPRequestOperationManager*)customHttpRequestOperationManager {
   AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
   manager.securityPolicy = [self customSecurityPolicy]; // SSL
   return manager;
}

+(void)getRequestWithUrl:(NSString*)url success:(void(^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void(^) (AFHTTPRequestOperation *operation, NSError *error))failure {
   [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
   AFHTTPRequestOperationManager *manager = [HttpClient customHttpRequestOperationManager];
   manager.responseSerializer = [AFHTTPResponseSerializer serializer];
   [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
       [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
       success(operation, responseObject);
   } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
       [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
       failure(operation, error);
   }];
}

谢谢!

1
你能够提供你的代码作为文本行内吗?这样做可以让其他人更容易地复制、修改和测试。 - David Snabel-Caunt
1
谢谢您的评论--我会的。 - davhab
9个回答

48

阅读了 AFNetworking 代码并检查了变更日志,以下是使其正常工作所需进行的操作。

使用 AFSSLPinningModeCertificate 创建您的 AFSecurityPolicy 对象:

AFSecurityPolicy* policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

默认情况下,AFNetworking会验证证书的域名。我们的证书是基于每个服务器生成的,并非所有证书都有域名,因此我们需要禁用它:

[policy setValidatesDomainName:NO];

由于证书是自签名的,它们在技术上是“无效的”,因此我们也需要允许它:

[policy setAllowInvalidCertificates:YES];

最后,AFNetworking将尝试验证整个证书链,但在我看来它只会一直向上验证到我们的CA,但出于某种原因它并没有这样做,因此我们也必须禁用它:

[policy setValidatesCertificateChain:NO];

就这些了!像你已经在做的那样在您的请求管理器中设置安全策略,它应该能很好地工作。

所以简单回顾一下,在你发布的代码中你需要改变的只有:

A) 如David Caunt所提到的,将您的固定模式从AFSSLPinningModeNone改为AFSSLPinningModeCertificate

B) 添加以下代码行来禁用验证域名:[policy setValidatesDomainName:NO]

另外请注意,AFNetworking现在会自动检查您的捆绑包中是否有.cer文件,因此如果您将证书重命名为.cer扩展名,则可以消除获取捆绑数据的代码并设置固定证书。


2
你应该将这个答案标记为已接受的。当我遇到NSURLErrorDomain code=-999 "cancelled"时,它对我很有用。节省了我大量的时间,谢谢! - HelloWorld
4
如果你通过Cocoapods使用动态框架(use_frameworks!),自动检测.cer文件可能无法正常工作。你可以切换到使用桥接头文件将AFNetworking集成到Swift项目中,这为我解决了这个问题。我怀疑这是由于动态框架的库文件位置不同导致的。 - kukudas
这个要加在哪里?我使用了通过CocoaPods动态框架,并且正在使用Objective C。 - Lion
我也使用CocoaPods来使用AFNetworking。你需要获取一个新的AFHTTPRequestOperationManager实例,并在该实例上调用setSecurityPolicy:,将你创建的AFSecurityPolicy传递给它。 - Jordan
@genaks 即使我也遇到了相同的问题,它发生在第一个请求时,对于下一个请求正常工作。你解决了吗? - VoidStack
显示剩余3条评论

25

既然您已经初始化了管理器,您可以执行以下操作:

manager.securityPolicy.allowInvalidCertificates = YES;
manager.securityPolicy.validatesDomainName = NO;

它将适用于自签名证书


5

我遇到了这个错误,Error Domain=NSURLErrorDomain Code=-1012 NSErrorFailingURLStringKey

仅通过以下更改,我成功解决了问题。

self.validatesDomainName = NO;

在应用了上述修复措施后,这对我来说也是必要的。 - d2burke

3
你正在创建一个带有SSLPinningMode模式为AFSSLPinningModeNoneAFSecurityPolicy
如果要让AFNetworking信任服务器,并将固定模式设置为AFSSLPinningModeNone,则必须将allowInvalidCertificates设置为YES,但这与你想要实现的相反。
相反地,你应该使用固定模式AFSSLPinningModeCertificateAFSSLPinningModePublicKey来创建你的安全策略:
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

2
你是否使用以下命令或类似命令将证书转换为DER格式?openssl x509 -in domain.crt -out domain.cer -outform der - David Snabel-Caunt
感谢@DavidCaunt。是的,传递给AFNetworking的证书已经转换为DER格式。 - davhab
1
如果将 validatesDomainName 设置为 NO,它是否有效?假设您的证书设置正确(正确的主机等),我会尝试这些步骤从服务器获取证书并以正确的格式获取它。否则,没有您的证书和 API 端点,我可能没有更多的想法了。 - David Snabel-Caunt
你之前有取得进展吗?我正在经历同样的问题,卡在同一个地方(AFServerTrustIsValid == NO)。在从 v. 2.3.1 升级到 2.5.0 后,此功能以前是可行的。 - Jordan
我也有一个类似的问题,但是在AFNetworking的版本1上。 - Marcel Gruber
显示剩余2条评论

1
- (AFSecurityPolicy *)securityPolicy {
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"*.something.co.in" ofType:@"cer"];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    [securityPolicy setAllowInvalidCertificates:YES];
    [securityPolicy setPinnedCertificates:@[certData]];
    [securityPolicy setValidatesDomainName:NO];
    [securityPolicy setValidatesCertificateChain:NO];
    return securityPolicy;
}

这对我很有帮助。出于某种原因,这对我有效。仍然不确定这会如何改变事情,因为我的应用程序中的其他连接在不执行所有这些步骤的情况下也可以工作。
这是生成安全策略时产生的错误样子 -
- (AFSecurityPolicy *)securityPolicy {
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"*.something.co.in" ofType:@"cer"];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    [securityPolicy setAllowInvalidCertificates:NO];
    [securityPolicy setPinnedCertificates:@[certData]];
    [securityPolicy setValidatesDomainName:YES];
    return securityPolicy;
}

现在遵循“不修补无损坏”的规则。

0

曾经遇到类似问题,通常情况下通过浏览器的HTTPS连接时一切看起来正常,因为许多浏览器会缓存第三方证书文件,这样它们就不必每次都加载。因此,你的证书链可能并没有完全被信任,就像你所认为的那样。

换句话说,使用浏览器进行安全连接可能看起来很好,但是根据你的AFNetworking设置,你的应用程序实际上可能无法接受你的证书链。在确保设置正确之后,下一步是确保你的证书链确实如你所想的那样好。下载一个名为SSL Detective的应用程序并查询你的服务器,你也可以使用www.ssldecoder.org。确保你的证书链中没有红色(未受信任)的项目,如果有,就在服务器上更改证书设置。

假设你的AFNetworking设置如下:

 [securityPolicy setAllowInvalidCertificates:NO];
 [securityPolicy setValidatesCertificateChain:NO];

可能是因为您的证书链是自签名的,所以它可能无法被接受。您还需要将那些参数切换为“是”。


0
对我来说,我的Podfile中设置了use_frameworks! - 该项目不使用Swift,我正在使用Pods来使用AFNetworking。将其注释掉,问题就解决了。

0
如果您只想消除警告而不需要客户端证书,则策略应如下所示:
AFSecurityPolicy* policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
[policy setValidatesDomainName:YES];
[policy setAllowInvalidCertificates:NO];

-2

我尝试了所有的方法,但都没有帮助,然后我搜索了这一行:

'NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");'

在这行下面,我将

'return NO;'

改为

'return YES;'

然后它就奏效了。

谢谢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接