【发布时间】:2020-04-06 04:58:51
【问题描述】:
注意:在 Android 对应应用程序上使用相同的 SSL 固定。那么 iOS 是否改变了一些东西?我的网址在服务器上是否有很多证书并且它们每天都在轮换?
问题是:
SSL Pinning 只能通过证书 pinning 来实现,那为什么不起作用呢?
如果有人清楚地解释了如何使用公钥来做到这一点?请解释一下。
首先我想解释一下我是如何获得本地证书的。我认为这很直接。我刚刚输入了https://ez-pay.io,然后我点击了锁图标并下载了证书。如果你明白我的意思。现在我认为这也可能是问题所在。我的问题是:下载证书的方法是否正确?
好吧,让我们假设这是正确的。我将证书嵌入或复制粘贴到我的 Xcode 项目中。
现在这里是获取远程(服务器)证书并将其与本地证书进行比较的代码:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
NSLog(@"SECURITY : didReceiveChallenge");
// REMOTE CERTIFICATE
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
// Evaluate server certificate [Whether the certificate is valid or not] --
SecTrustResultType result;
SecTrustEvaluate(serverTrust, &result);
BOOL isRemoteCertValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
// Remote certificate object --
SecCertificateRef certificateRemote = SecTrustGetCertificateAtIndex(serverTrust, 0);
// Returns a DER representation of a certificate --
NSData *remoteCertData = CFBridgingRelease(SecCertificateCopyData(certificateRemote));
NSData *localCerData = [self GetLocalCertificateData];
// base 64 encoding of remote certificate --
NSString* strRemote = [remoteCertData base64EncodedStringWithOptions:0]; // get string from certificate --
NSString *strLocal = [self GetLocalCertificateStringForPublicKey];
// The pinning check -- compare the remote and local certificate data / string --
// if (isRemoteCertValid && [strLocal isEqualToString:strRemote] )
if (isRemoteCertValid && [localCerData isEqualToData:remoteCertData] )
{
NSLog(@"SECURITY : OK ");
}
else
{
NSLog(@"SECURITY : FAILS");
isCertificateValid = false;
}
}
- (NSData *)GetLocalCertificateData
{
if ( MODE == PROD_US)
{
NSString *pathToCert = [[NSBundle mainBundle]pathForResource:@"prod_ezpay" ofType:@"cer"];
NSData *localCertificate = [NSData dataWithContentsOfFile:pathToCert];
return localCertificate;
}
else if (MODE == PREP_US)
{
NSString *pathToCert = [[NSBundle mainBundle]pathForResource:@"prepEZPAY" ofType:@"cer"];
NSData *localCertificate = [NSData dataWithContentsOfFile:pathToCert];
return localCertificate;
}
return nil;
}
现在的问题是证书数据的比较总是失败:
[localCerData isEqualToData:remoteCertData] // Always false
我一直在尝试许多不同的方法,在 google 上检查了 5-6 个链接,都具有相同的方法。这个项目有点老了,3-4年,用Objective-C写的。
我尝试了 3 种方法:
将证书转换为 NSData 并进行比较 -- 无效。
将证书转换为 NSData,然后转换为 Base64String - 无效..
也是一个 hack - 我打印了数据并以字符串格式保存并在应用程序中硬编码,然后下次继续将其与服务器的证书数据进行比较。这种方法仅适用于一天和第二天服务器的证书数据更改。不知道发生了什么。
请指出这里有什么问题?
【问题讨论】:
-
“这种方法只适用于一天和第二天服务器的证书数据更改”服务器证书可以在每次连接时更改。你真正想做什么,你想比较什么,为什么?
-
@PatrickMevzek 我想在我的 iOS 应用程序中启用 SSL 固定。而且我很难固定证书。为什么证书会改变?如果你去 htps://ez-pay.io 下载证书并检查它的到期日期,你会发现它只会在一年左右之后才会改变..简而言之,我尝试了大多数可能的方法来在 iOS、ObjC 中进行 SSL 固定,10 天以来没有运气。
-
"还有为什么证书会改变?"因为它们过期了,一个。因为在单个网站名称后面,您可以拥有一组服务器,并且绝对不需要所有服务器都拥有完全相同的证书,它只需要是该名称的有效证书即可。希望证书永远保持不变是行不通的。
-
"你会看到一年左右才会改" False。它可以随时更改。到期日期意味着它必须在此日期之前更改,因为在该日期之后它不再有效。它没有说明什么时候可以在到期前更改。可以随时更改,次数不限。
-
好的。如果我假设域名后面有一个证书链,即 ez-pay.io 仍然,上面的代码应该可以工作。到目前为止,我已经在 google 上搜索了近 10 个链接,并且都给出了相同的答案。您认为我在 ios 应用中使用 SSL Pinning 的方法是正确的吗?
标签: ios objective-c ssl ssl-certificate