nginx與ios實現https雙向認證

來源:互聯網
上載者:User

服務端配置

nginx關鍵配置如下:

listen       443;server_name  localhost;ssl on;ssl_certificate      /usr/local/opt/nginx/certificates/server.cer;ssl_certificate_key  /usr/local/opt/nginx/certificates/server.key.pem;ssl_client_certificate /usr/local/opt/nginx/certificates/ca.cer;ssl_verify_client    on;


ssl開啟https

ssl_certificate是服務端認證的路徑,ssl_certificate_key是服務端私密金鑰的路徑

ssl_verify_client是配置雙向認證(client certificate)

ssl_client_certificate是簽發用戶端認證的根憑證

為什麼是根憑證,因為可以簽發很多用戶端認證,只要是由該根憑證簽發的,服務端都視為認證通過

配置完成以後,一般需要把80連接埠的http請求跳轉到443連接埠,否則使用者可以通過80連接埠以http方式訪問,就失去了安全保護的意義

用戶端代碼

在網上找了很多ios client certificate的文章,要麼是代碼不全,要麼是很老的文章,還是用的NSURLConnection,delegate method都deprecated了,最後找了一個程式碼片段,改了一下

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];    NSURL *url = [NSURL URLWithString:@"https://localhost/svc/portal/setting"];    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];[request setHTTPShouldHandleCookies:NO];[request setTimeoutInterval:30];[request setHTTPMethod:@"GET"];    NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {    NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];    NSLog(@"%@", message);}];    [task resume];

上面的程式碼片段,是用NSURLSessionDataTask發起https請求。在ssl握手階段,會調用2次下面的delegate method

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler{    NSString *method = challenge.protectionSpace.authenticationMethod;    NSLog(@"%@", method);        if([method isEqualToString:NSURLAuthenticationMethodServerTrust]){                NSString *host = challenge.protectionSpace.host;        NSLog(@"%@", host);                NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);        return;    }    NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];    CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(PKCS12Data);    SecIdentityRef identity;        // 讀取p12認證中的內容    OSStatus result = [self extractP12Data:inPKCS12Data toIdentity:&identity];    if(result != errSecSuccess){        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);        return;    }        SecCertificateRef certificate = NULL;    SecIdentityCopyCertificate (identity, &certificate);        const void *certs[] = {certificate};    CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);        NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)CFBridgingRelease(certArray) persistence:NSURLCredentialPersistencePermanent];        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);}-(OSStatus) extractP12Data:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity {        OSStatus securityError = errSecSuccess;        CFStringRef password = CFSTR("the_password");    const void *keys[] = { kSecImportExportPassphrase };    const void *values[] = { password };        CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);    securityError = SecPKCS12Import(inP12Data, options, &items);        if (securityError == 0) {        CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);        const void *tempIdentity = NULL;        tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);        *identity = (SecIdentityRef)tempIdentity;    }        if (options) {        CFRelease(options);    }        return securityError;}

上面的程式碼片段,即拷即用,希望能有所協助。這個方法會被調用2次,第一次是ios app驗證server的階段,第二次是server驗證ios app的階段,即client certificate。關鍵是每個階段的校正完成以後,要調用completionHandler方法。網上的大部分文章都是

[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];

這行代碼是無效的

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.