美文网首页收藏ios疯狂iOS
CocoaHttpServer 实现https

CocoaHttpServer 实现https

作者: 花了个缺 | 来源:发表于2018-04-04 10:27 被阅读663次

    前言

    苹果在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<HTTPResponse> *)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

      本文链接:https://www.haomeiwen.com/subject/zduchftx.html