https://www.cnblogs.com/lizilong/p/7527305.html
处于安全的考虑需要https请求,但是为了防止域名解析很多情况下会使用IP进行访问。
一般的服务不会针对IP去申请证书,所以我们可以自己实现ssl登录过程,保证请求的安全性。
一.首先需要自己本地生成ssl证书以及搭建一个本地服务
Mac apache本地配置ssl证书 及 iOS OTA部署: http://www.jianshu.com/p/bd016015efe7
生成的crt转换成cer的方法
openssl x509 -in test.crt -out test.cer -outform der
二.实现代码
初始化NSURLSession,将证书导入对应的xcode项目中
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.timeoutIntervalForRequest = 120;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
生成的ssl证书需要设置ip,而且校验的时候也会去校验这个ip。但是更多情况下是不去校验这个ip的,因为代码内部可能只有一个证书,但是服务可能会有多套部署,如果去校验ip,会限制服务的扩展(很多项目都会做自己的DNS策略,ip经常会改变)。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
NSString *host = challenge.protectionSpace.host;
BOOL isIp = [self _isIp:host];
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if (isIp) {
// Get
NSData *certData =[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"]];
if (certData) {
SecTrustRef trust = [[challenge protectionSpace] serverTrust];
NSMutableArray *policies = [NSMutableArray array];
//如果需要校验IP,需要把下面的注释打开,把下面X509这段代码注释掉
//[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
SecTrustSetPolicies(trust, (__bridge CFArrayRef)policies);
SecCertificateRef rootcert = SecCertificateCreateWithData(kCFAllocatorDefault,CFBridgingRetain(certData));
const void *array[1] = { rootcert };
CFArrayRef certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, certs);
if (err == noErr) {
err = SecTrustEvaluate(trust,&trustResult);
}
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));
if (!trusted) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] ;
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
//如果校验失败了,就校验一下证书数据,一般不建议走这段逻辑,因为不能够保证服务是否安全
NSMutableArray *pinnedCertificates = [NSMutableArray array];
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData)];
SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)pinnedCertificates);
NSArray *serverCertificates = [self _certificateTrustChainForServerTrust:trust];
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
if ([certData isEqualToData:trustChainCertificate]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] ;
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}
}
}
}
} else {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}
}
}
- (BOOL)_isIp:(NSString*)aHost
{
NSString *regex = @"((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
return [pred evaluateWithObject:aHost];
}
- (NSArray *)_certificateTrustChainForServerTrust:(SecTrustRef)serverTrust
{
CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
for (CFIndex i = 0; i < certificateCount; i++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
[trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
}
return [NSArray arrayWithArray:trustChain];
}
https请求构建
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://127.0.0.1:443/index.html"]];
NSURLSessionDataTask *task = [_session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
completionHandler(((NSHTTPURLResponse*)response).statusCode, data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : nil, error);
}];
[task resume];
网友评论