Xcode中的证书固定化

6
我得到了以下证书代码 在安卓中固定
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开发者不熟悉Android。 - KudoCC
我也是... :D 哈哈,需要根据客户要求为IOS编写类似的代码。 - 9to5ios
1
你看过Alamofire吗?它可以处理HTTPS的证书固定。https://github.com/Alamofire/Alamofire - Flexicoder
1
请查看此链接:https://infinum.co/the-capsized-eight/how-to-make-your-ios-apps-more-secure-with-ssl-pinning - Dimple Shah
1个回答

2
如果身份验证方法是NSURLAuthenticationMethodServerTrust,则if块跳过证书固定。我不太确定为什么要这样做 - 您需要查看获取此代码片段的源代码并了解其要求。
如果身份验证方法是其他任何内容,则else块会执行证书固定。
变量serverTrust从服务器发送到SSL事务状态。这里的主要问题是它具有验证服务器的证书链。在下一行中,certificate设置为链中的叶证书,即服务器的证书。 remoteCertificateData本质上是表示证书中信息的大型二进制数据块。调用CFBridgingRelease是为了内存管理(所有CFxxx函数都是C / C ++函数,而不是Objective-C,因此内存管理比正常情况稍微复杂一些)。 localCertData是证书本地副本中信息的二进制数据块。请注意,iOS应用程序(或多或少)是包括可执行文件以及各种资源等文件的集合。作为构建过程的一部分,您将安排包含服务器证书的副本在这些文件的(NSBundle)集合中。 cerPath变量设置为本地证书副本的文件路径。
最后,我们检查两个二进制数据块是否相等。如果不是,则服务器证书无效,我们不会继续请求。
我不完全确定您所说的“需要发送乘数证书”的意思。根据您引用的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");

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