CocoaHttpServer 實現(xiàn)https

前言

蘋果在iOS9中加入了ATS,不清楚的同學(xué)點擊任意門ATS適配, 當(dāng)然這個其實也是蠻好的,安全嘛,這篇文章的主題是講如何用CocoaHttpServer 實現(xiàn)https.

生成自簽名證書

OpenSSL官網(wǎng)下載最新版本,解壓之后拷貝demoCA到你想要放的文件夾,當(dāng)然你也可以自己生成一個demoCA,在app目錄中找到CA.sh,拷貝到你的目錄,執(zhí)行

sh ./CA.sh -newca

然后創(chuàng)建一個目錄

 mkdir server

創(chuàng)建一個私鑰

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

創(chuàng)建證書請求

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   注釋:一定要寫服務(wù)器所在的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

將證書導(dǎo)出成瀏覽器支持的.p12格式,記得導(dǎo)出密碼

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(調(diào)用 startServer )之前,使用 setConnectionClass 方法將 HTTPConnecdtion 替換為 MyHTTPConnection

[_httpServer setConnectionClass:[MyHTTPConnection class]];

WKWebView代理配置

WKWebView需要在WKNavagationDelegate方法中允許使用,這個方法和AFNetworking處理方法很相似,當(dāng)然你如果是用safari打開對應(yīng)的鏈接的話,就得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設(shè)置

App Transport Security Settings添加Allow Arbitrary Loads in Web Content設(shè)置為YES

結(jié)束

附上我自己寫的小demo, 打完收工?。?!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容