【问题标题】:Problems with SSL Pinning and AFNetworking 2.5.0 (NSURLErrorDomain error -1012.)SSL Pinning 和 AFNetworking 2.5.0 的问题(NSURLErrorDomain 错误 -1012。)
【发布时间】:2015-03-04 16:27:58
【问题描述】:

我们一直很难使用 AFNetworking 2.5.0 通过 SSL 保护我们应用的网络连接。

我们使用自签名证书颁发机构并使用固定证书实施自定义安全策略。

我们已经测试了很多 AFNetworking 提供的配置,但到目前为止都不是很幸运。我们收到的错误信息是:

2015-01-05 19:03:07.191 AppName[9301:319051] 更新用户时出错 旅行。错误:错误域=NSURLErrorDomain 代码=-1012 " 操作无法完成。 (NSURLErrorDomain 错误 -1012。)” 用户信息=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);
   }];
}

谢谢!

【问题讨论】:

  • 您能以文本形式提供您的内联代码吗?这使得其他人更容易复制/修改/测试。
  • 感谢您的评论 -- 会的。

标签: ios ssl afnetworking afnetworking-2


【解决方案1】:

在阅读了 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 扩展名,您可以消除从捆绑包中获取证书数据的代码并设置固定证书。

【讨论】:

  • 您应该将此标记为已接受的答案。当我有一个 NSURLErrorDomain 代码=-999“已取消”时为我工作。为我节省了大量时间,谢谢!
  • 如果你通过 Cocoapods 使用动态框架(use_frameworks!)。 .cer 文件的自动检测可能不起作用。您可以切换到使用桥接头将 AFNetworking 集成到一个 swift 项目中,该项目为我解决了这个问题。我怀疑这是因为 lib 的位置不同,如果它是一个动态框架。
  • 在哪里添加这个?我通过 Cocoa pods 使用动态框架,我正在使用目标 C。
  • 我也通过 CocoaPods 使用 AFNetworking。您想获得一个新实例 AFHTTPRequestOperationManager 并在该实例上调用 setSecurityPolicy:,将您创建的 AFSecurityPolicy 传递给该实例。
  • 我非常随机地看到这个错误。假设我在与 URL 建立的第一个连接中看到了这个,在我建立的下一个连接中它不会出现。如果不是这么随机,我就不会担心。
【解决方案2】:

既然你已经初始化了管理器,你可以这样做:

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

它适用于自签名证书

【讨论】:

    【解决方案3】:

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

    仅以下更改就可以为我工作。

    self.validatesDomainName = NO;
    

    【讨论】:

    • 在应用上述修复后,这对我来说也是必要的
    【解决方案4】:

    您正在使用SSLPinningMode 模式AFSSLPinningModeNone 创建AFSecurityPolicy

    要使 AFNetworking 信任服务器,将固定模式设置为 AFSSLPinningModeNone,您必须将 allowInvalidCertificates 设置为 YES,但这与您要实现的目标相反

    相反,您应该使用固定模式 AFSSLPinningModeCertificateAFSSLPinningModePublicKey 创建安全策略:

    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    

    【讨论】:

    • 感谢您的回答@DavidCaunt。事实上,我们已经尝试过AFSSLPinningModeCertificateAFSSLPinningModePublicKeyAFSSLPinningModeNone,但它们似乎都不起作用。还有其他指针吗?再次感谢。
    • 您是否使用以下或类似方法将您的证书转换为 DER 格式? openssl x509 -in domain.crt -out domain.cer -outform der
    • 感谢@DavidCaunt。是的,传递给 AFNetworking 的证书已转换为 DER 格式。
    • 如果您将validatesDomainName 设置为NO 是否有效?假设您的证书设置正确(正确的主机等),我会尝试these steps 从服务器获取证书并以正确的格式获取它。否则,如果没有您的证书和 API 端点,我可能没有想法。
    • 嗨@DavidCaunt。不幸的是没有。我已按照您提供的步骤进行操作,但没有运气。我现在正在调查 AFNetworking 内部发生的事情。在AF_Require_noErr(SecTrustEvaluate(serverTrust, &result), _out) 之后result 中的值是5 (kSecTrustResultRecoverableTrustFailure) 所以AFServerTrustIsValid 返回NO 并且提供的证书被认为是无效的。
    【解决方案5】:
    - (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;
    }
    

    现在坚持“如果没有损坏就不要修复”的规则

    【讨论】:

      【解决方案6】:

      在处理过类似问题后,通过浏览器 HTTPS 连接看起来很正常的情况很常见,因为许多浏览器会缓存来自第三方的证书文件,因此它们并不总是需要加载。因此,很可能您的证书链并不完全受信任,正如您可能被引导相信的那样。

      换句话说,使用浏览器安全连接似乎没问题,但根据您的 AFNetworking 设置,您的应用实际上不会接受您的证书链。在您确定您的设置合适之后,下一步是确保您的证书链实际上与您想象的一样好。下载一个名为 SSL Detective 的应用程序并查询您的服务器。您也可以使用www.ssldecoder.org。确保您的链中没有红色(不受信任)项目。如果有,请更改服务器上的证书设置。

      鉴于您的 AFNetworking 设置如下:

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

      它可能不喜欢您的证书链,因为它是自签名的。您可能还必须将它们切换为“是”。

      【讨论】:

        【解决方案7】:

        对我来说,我在我的Podfile 中设置了use_frameworks! - 该项目没有使用 Swift,而我使用Pods 代替AFNetworking。对此发表评论,为我解决了这个问题。

        【讨论】:

          【解决方案8】:

          如果您只想在没有客户端证书的情况下消除警告,则策略应如下所示:

          AFSecurityPolicy* policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
          [policy setValidatesDomainName:YES];
          [policy setAllowInvalidCertificates:NO];
          

          【讨论】:

            【解决方案9】:

            我尝试了所有这些但没有任何帮助然后我搜索了这一行

            'NSLog(@"为了验证自签名证书的域名,您必须使用 pinning。");'

            在这条线下面我改变了

            '返回NO;'

            '返回是;'

            它发挥了魔力。

            谢谢。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2016-02-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-03-30
              • 2014-05-12
              相关资源
              最近更新 更多