CocoaHttpServer 实现https

前言

苹果在iOS9中加入了ATS,不清楚的同学点击任意门ATS适配, 当然这个其实也是蛮好的,安全嘛,这篇文章的主题是讲如何用CocoaHttpServer 实现https.

生成自签名证书

到OpenSSL官网下载最新版本,解压之后拷贝demoCA到你想要放的文件夹,当然你也可以自己生成一个demoCA,在app目录中找到CA.sh,拷贝到你的目录,执行

sh ./CA.sh -newca

然后创建一个目录

 mkdir server

创建一个私钥

openssl genrsa -out server/server-key.pem 2048

创建证书请求

openssl req -new -out server/server-req.csr -key server/server-key.pem

然后会需要填写一系列信息

Country Name (2 letter code) [AU]:cn 
State or Province Name (full name) [Some-State]:fujian
Locality Name (eg, city) []:xiamen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test 
Organizational Unit Name (eg, section) []:test 
Common Name (eg, YOUR name) []:127.0.0.1   注释:一定要写服务器所在的ip地址 
Email Address []:sky 

Common Name 这一项必须填 localhost 或者 127.0.0.1 ,如果填写127.0.0.1,那么页面中请求只能使用https://127.0.0.1:60000 而不能使用 https://localhost:60000,反之相同。

自签署证书

openssl x509 -req -in server/server-req.csr -out server/server-cert.pem -signkey server/server-key.pem -CA demoCA/cacert.pem -CAkey demoCA/private/cakey.pem -CAcreateserial -days 3650

将证书导出成浏览器支持的.p12格式,记得导出密码

openssl pkcs12 -export -clcerts -in server/server-cert.pem -inkey server/server-key.pem -out server/server.p12

自签名证书生成完成。

工程配置

将生成的p12放到工程目录下面,同时新建一个 MyHttpConnection 继承于 HttpConnection ,重载 - (BOOL)isSecureServer 方法及 sslIdentityAndCertificates 方法

- (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:@"TestCertificate" 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;
}

- (NSObject *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
{
    // do something
    return [super httpResponseForMethod:method URI:path];
}

同时在启动 HTTPServer(调用 startServer )之前,使用 setConnectionClass 方法将 HTTPConnecdtion 替换为 MyHTTPConnection

[_httpServer setConnectionClass:[MyHTTPConnection class]];

WKWebView代理配置

WKWebView需要在WKNavagationDelegate方法中允许使用,这个方法和AFNetworking处理方法很相似,当然你如果是用safari打开对应的链接的话,就得safari允许自签名的证书。

  - (void)webView:(WKWebView *)webView  didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge  completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
      if ([challenge.protectionSpace.authenticationMethod  isEqualToString:NSURLAuthenticationMethodServerTrust]) {
          NSURLCredential *card = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
          completionHandler(NSURLSessionAuthChallengeUseCredential, card);
      }
  }

ATS设置

App Transport Security Settings添加Allow Arbitrary Loads in Web Content设置为YES

结束

附上我自己写的小demo, 打完收工!!!

你可能感兴趣的:(CocoaHttpServer 实现https)