nginx 와 ios 는 https 양 방향 인증 을 실현 합 니 다.

5075 단어
서버 설정
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 sslcertificate 는 서버 인증서 의 경로 입 니 다. sslcertificate_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];

위의 코드 세 션 은 NSURLSession DataTask 로 https 요청 을 합 니 다.ssl 악수 단계 에서 아래 delegate method 를 2 회 호출 합 니 다.
- (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;
}

위의 코드 세 션 은 복사 하거나 사용 할 수 있 으 니 도움 이 되 기 를 바 랍 니 다.이 방법 은 두 번 호출 됩 니 다. 첫 번 째 는 ios app 이 server 를 검증 하 는 단계 이 고 두 번 째 는 server 가 ios app 을 검증 하 는 단계 입 니 다. 즉, client certificate 입 니 다.관건 은 각 단계 의 검증 이 끝 난 후에 completionHandler 방법 을 호출 하 는 것 이다.인터넷 에 올 라 오 는 댓 글 대부분이...
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];

이 줄 코드 는 유효 하지 않 습 니 다.

좋은 웹페이지 즐겨찾기