【问题标题】:Certificate pinning in XcodeXcode 中的证书固定
【发布时间】:2017-05-31 19:24:16
【问题描述】:

我得到以下证书代码pinning in Android

CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
.add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
.add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
.add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
.build();

如何使用 NSURLSession 方法在 IOS 中完成相同的任务?

这里有一些参考代码

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"MyLocalCertificate" ofType:@"cer"];
NSData *localCertData = [NSData dataWithContentsOfFile:cerPath];
if ([remoteCertificateData isEqualToData:localCertData]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}

编辑部分

我得到了以下解决方案,在 NSURLSession 中自动调用了哪个委托函数,谁能解释它是如何工作的?还需要发送乘数证书我该怎么做?

 (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
    NSString *authMethod = [[challenge protectionSpace] authenticationMethod];

    if ([authMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
    } else {
        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
        NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"MyLocalCertificate" ofType:@"cer"];
        NSData *localCertData = [NSData dataWithContentsOfFile:cerPath];
        NSURLCredential *credential;

        if ([remoteCertificateData isEqualToData:localCertData]) {
             credential = [NSURLCredential credentialForTrust:serverTrust];
            [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
        }
        else {
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }



        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        NSLog(@"Finished Challenge");
    }
}

【问题讨论】:

标签: ios objective-c iphone xcode


【解决方案1】:

如果身份验证方法为NSURLAuthenticationMethodServerTrust,则 if 块跳过证书固定。我不太确定你为什么要这样做——你必须查看你得到这个代码 sn-p 的源代码,看看它的要求是什么。

如果身份验证方法是其他方法,则 else 块执行证书固定。

变量serverTrust从服务器发送到SSL事务状态。这里的主要内容是它有一个证书链来验证服务器。在下一行中,certificate 设置为链中的叶子证书,即服务器的证书。

remoteCertificateData 本质上是一个大的二进制 blob,表示证书中的信息。内存管理需要调用CFBridgingRelease(所有CFxxx函数都是C/C++函数,不是Objective-C,内存管理比平时复杂一点)。

localCertData 是证书本地副本中信息的二进制 blob。请注意,iOS 应用程序(或多或少)是文件的集合,包括可执行文件以及各种资源等。作为构建过程的一部分,您将安排将服务器证书的副本包含在这些集合中(@ 987654328@) 个文件。 cerPath 变量设置为证书本地副本的文件路径。

最后,我们检查两个二进制 blob 是否相等。如果不是,那么来自服务器的证书是伪造的,我们不会继续请求。

我不完全确定“需要发送乘数证书”是什么意思。从您引用的 Java 代码来看,我假设您的意思是要将服务器证书与多个本地证书进行比较。在这种情况下,(大致)类似于以下内容(注意:未经测试的代码):

   SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
   SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
   NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));

   BOOL match = NO;
   NSURLCredential *credential;

   for (NSString *path in [[NSBundle mainBundle] pathsForResourcesOfType:@"cer" inDirectory:@"."]) {
          NSData *localCertData = [NSData dataWithContentsOfFile:path];

          if ([remoteCertificateData isEqualToData:localCertData]) {
              credential = [NSURLCredential credentialForTrust:serverTrust];
              match = YES;
              break;
          }
   }       

   if (match) {
      [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
   } else {
      [[challenge sender] cancelAuthenticationChallenge:challenge];
   }

   completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
   NSLog(@"Finished Challenge");

【讨论】:

    猜你喜欢
    • 2018-10-28
    • 2017-02-14
    • 2019-10-08
    • 1970-01-01
    • 2016-04-09
    • 2019-02-16
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    相关资源
    最近更新 更多