背景
- iOS采用cocoalhttpserver搭建的本地服务器 通过本地HTTP Server与网页端交互
- 网页端支持 HTTPS的话,因为HTTP、HTTPS网页内容混合会导致请求异常(因为在https页面发起http请求会被block掉)
- 例如使用 https://localhost:5543f3 访问iOS搭建的服务端,会无法接受到数据(因为服务端只有http,发起https则找不到iOS服务端地址)
解决方法
让iOS移动端 HTTP Server 支持 HTTPS
配置证书
自签证书的不安全性,并且浏览器会提示
不安全
,需要用户选择是否继续前往,所以不考虑,
公共证书的话,因为localhost
或 127.0.0.1
的不唯一性,是不允许生成公共SSL证书。
经过查找资料,可以通过自有域名指向127.0.0.1
来解决这个问题,
具体办法:
比如你有域名为local.xxxxx.cn这个子域名 指向服务器地址466.111.111
可通过 FreeSSL 为自由域名配置免费的SSL证书
最后下载证书会得到自由域名的SSL证书文件夹,包含如下:
(假设导出为cer则双击导入,然后在导出为pem)
证书申请下来之后,将该域名指向127.0.0.1即可
使用openssl命令导出p12
openssl pkcs12 -export -clcerts -in full_chain.pem -inkey private.key -out my.p12
iOS端配置
先将导出的p12文件导入到项目中,要确保时导入而不是引用
参考之前的博文https://blog.youkuaiyun.com/u012717715/article/details/89641415
可以直接在Routing目录下的RoutingConnection下直接复制一下代码到项目中
其中password为你导出p12文件时设置的密码
- (BOOL)isSecureServer
{
// Create an HTTPS server (all connections will be secured via SSL/TLS)
return YES;
}
/**
* This method is expected to returns an array appropriate for use in kCFStreamSSLCertificates SSL Settings.
* It should be an array of SecCertificateRefs except for the first element in the array, which is a SecIdentityRef.
**/
- (NSArray *)sslIdentityAndCertificates
{
SecIdentityRef identityRef = NULL;
SecCertificateRef certificateRef = NULL;
SecTrustRef trustRef = NULL;
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"my" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(PKCS12Data);
CFStringRef password = CFSTR("123");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = errSecSuccess;
securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
identityRef = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
trustRef = (SecTrustRef)tempTrust;
} else {
NSLog(@"Failed with error code %d",(int)securityError);
return nil;
}
SecIdentityCopyCertificate(identityRef, &certificateRef);
NSArray *result = [[NSArray alloc] initWithObjects:(id)CFBridgingRelease(identityRef), (id)CFBridgingRelease(certificateRef), nil];
return result;
}
以上配置完成后使用:https://local.xxxxx.cn:55433即可访问安全的https链接,发起get、post都没有任何问题
最后总结一下配置过程中可能碰到配置完成后还是无法访问https的问题:
1、可以判断p12文件是否导入项目,以及路径是否寻找正确
2、确保iOS项目中代码所有的请求都为https请求,因为ssl配置服务器的时候,如果服务器中含有http请求,同样会出现不安全的ssl情况
3、在GCDAsyncSocket.m文件中注释该段代码
// if (value)
// {
// NSAssert(NO, @"Security option unavailable - kCFStreamSSLLevel"
// @" - You must use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMax");
//
// [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLLevel"]];
// return;
// }