iOS 개발 에 대한 자세 한 설명-AFNetworking 으로 https 단 방향 검증,양 방향 검증 실현
이 를 감안 하여 블 로 거들 은 이 구 덩이 를 메 우 고 정확 한 코드 를 추가 하여 많은 개발 자 들 이 사용 할 수 있 도록 하려 고 했 으 나 나중에 방치 되 었 다.시 도 를 거 친 후에 블 로 거들 은 정 리 된 코드 를 여기에 발표 하여 애타게 찾 는 개발 자 에 게 도움 이 되 기 를 바란다.
1.오래된 AFNetworking 2.x 가 어떻게 이 루어 졌 는 지 먼저 말 해 보 자.
블 로 거들 은 인터넷 에서 몇 편의 게시 물 을 보 았 는데 그 중에서 말 하 는 방법 이 정확 하지만 모두 옳 은 것 은 아니다.그 몇 편의 블 로 그 는 거의 똑 같 기 때문에 블 로 거들 은 최초의 그 편 을 누가 썼 는 지 확정 할 수 없 기 때문에 다음 과 같은 방법 을 다시 설명 한다.
1)client.p12 인증 서 를 불 러 오기;
2)plist 파일 에서 그림 설정:
3)AFNetworking 에서 클래스 수정:
이 파일 을 찾 으 면 안에 방법 을 추가 합 니 다.
- (OSStatus)extractIdentity:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity {
OSStatus securityError = errSecSuccess;
CFStringRef password = CFSTR(" ");
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;
}
다시 한 가지 방법 을 수정 합 니 다.NSURLConnection Delegate 의 동명 코드 를 아래 코드 로 교체 합 니 다.
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
// NSLog(@"thePath===========%@",thePath);
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
SecIdentityRef identity = NULL;
// extract the ideneity from the certificate
[self extractIdentity :inPKCS12Data toIdentity:&identity];
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
// CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
// create a credential from the certificate and ideneity, then reply to the challenge with the credential
//NSLog(@"identity=========%@",identity);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:nil persistence:NSURLCredentialPersistencePermanent];
// credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
4)요청
NSString *url = @"xxxxxxxxxx";
// 1.
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//2 https
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
securityPolicy.allowInvalidCertificates = YES;
mgr.securityPolicy = securityPolicy;
// 3. POST
[mgr POST:url parameters:nil success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSLog(@"responseObject: %@", responseObject);
} failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
NSLog(@"Error: %@", error);
}];
이로써 기 존의 AFNetworking 은 https 인터페이스의 양 방향 검증 을 요청 하면 끝 났 습 니 다.그러나 문제 가 있 습 니 다.여기 서 AFNetworking 코드 를 바 꿔 야 합 니 다.게다가 새로운 AFNetworking 은 이미 있 습 니 다.코드 의 활력 을 유지 하기 위해 오래된 것 은 버 려 야 합 니 다.그리고 pods 를 업데이트 한 후에 반드시 바 꿀 코드 가 없어 지 는 것 도 문제 입 니 다.서 두 르 지 마 세 요.새로운 AFNetworking 을 어떻게 사용 하 는 지,pods 에 의 해 교체 코드 가 업데이트 되 는 문 제 를 해결 하 는 방법 을 알려 드 리 겠 습 니 다.마지막 으로 한 가지 더 말씀 드 리 지만 오래된 AF 를 사용 하여 요청 합 니 다.client.p12 파일 만 사 용 했 고 server.cer 를 사용 하지 않 았 습 니 다.새로운 것 에서 유용 합 니 다.클 라 이언 트 가 모든 인증 서 를 신뢰 하 는 것 을 선택 한 것 으로 추정 되 고 일방적인 검증 이 되 었 습 니 다.
데 모 는 마지막 에.
2.새로운 AFNetworking 3.x 가 어떻게 이 루어 졌 는 지 말 해 보 자.
1)client.p12 와 server.cer 파일 을 불 러 옵 니 다.
2)plist 내의 설정,이것 은 위 와 같은 것 입 니 다:
3)여 기 는 클래스 의 코드 를 수정 할 필요 가 없 지만,여 기 는 방법 을 다시 써 야 합 니 다.
NSString *url = @"https://test.niuniuhaoguanjia.com/3.0.0/?service=City.GetCityList";
NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
NSSet *certSet = [NSSet setWithObject:certData];
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:certSet];
policy.allowInvalidCertificates = YES;
policy.validatesDomainName = NO;
_manager = [AFHTTPSessionManager manager];
_manager.securityPolicy = policy;
_manager.requestSerializer = [AFHTTPRequestSerializer serializer];
_manager.responseSerializer = [AFHTTPResponseSerializer serializer];
_manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain", nil];
// r
_manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
[_manager setSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) {
NSLog(@"setSessionDidBecomeInvalidBlock");
}];
// setSessionDidReceiveAuthenticationChallengeBlock
__weak typeof(self)weakSelf = self;
[_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) {
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__autoreleasing NSURLCredential *credential =nil;
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if(credential) {
disposition =NSURLSessionAuthChallengeUseCredential;
} else {
disposition =NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
// client authentication
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"p12"];
NSFileManager *fileManager =[NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:p12])
{
NSLog(@"client.p12:not exist");
}
else
{
NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];
if ([[weakSelf class]extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data])
{
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate(identity, &certificate);
const void*certs[] = {certificate};
CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);
credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
disposition =NSURLSessionAuthChallengeUseCredential;
}
}
}
*_credential = credential;
return disposition;
}];
4)요청
// ,
[_manager GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
NSLog(@"JSON: %@", dic);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"Error: %@", error);
NSData *data = [error.userInfo objectForKey:@"com.alamofire.serialization.response.error.data"];
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",str);
}];
또 하나의 방법 을 더 해 야 한다.
+(BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
OSStatus securityError = errSecSuccess;
//client certificate password
NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@" "
forKey:(__bridge id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
if(securityError == 0) {
CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0);
const void*tempIdentity =NULL;
tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void*tempTrust =NULL;
tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);
*outTrust = (SecTrustRef)tempTrust;
} else {
NSLog(@"Failedwith error code %d",(int)securityError);
return NO;
}
return YES;
}
맞 아,우 리 는 포장 을 해 야 하 는데 어떻게 포장 해 야 하지?블 로 거들 은 집중 을 시 도 했 지만 모두 실 패 했 습 니 다.정말 이해 할 수 없습니다.주동 적 으로 포장 을 하 는 개발 자 들 도 포장 을 한 후에 실 패 를 요청 하 는 문제 에 부 딪 힐 것 이 라 고 믿 습 니 다.성공 할 수도 있 습 니 다.하지만 여기 서 block 에서 변 수 를 사용 하 는 문 제 를 주의해 야 합 니 다.구체 적 으로 블 로 거들 이 어떻게 포장 하 는 지 볼 수 있 습 니 다.여기까지 새로운 AF 요청 https 가 끝 났 습 니 다.봉 인 된 것 을 보고 싶 으 면 Demo 를 마지막 에 놓 으 세 요.
3.단 방향 검증
이 쯤 되면 인터넷 의 많은 방법 을 말 하지 않 을 수 없다.모두 단 방향 검증 을 양 방향 으로 하 는데 사실은 그 원 리 를 이해 하지 못 한다.원리 에 대해 서 는 여 기 를 보 세 요.
코드 구현 AF 는 모두 같 습 니 다:
//AF
_manager.securityPolicy = [self customSecurityPolicy];
/**** SSL Pinning ****/
- (AFSecurityPolicy*)customSecurityPolicy {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setAllowInvalidCertificates:YES];
NSSet *set = [NSSet setWithObjects:certData, nil];
[securityPolicy setPinnedCertificates:@[certData]];
/**** SSL Pinning ****/
return securityPolicy;
}
4.데모 다운로드 혜택인증서 보안 문제 로 데모 의 인증서 블 로 거들 이 삭 제 했 습 니 다.양 해 를 바 랍 니 다.자신의 인증 서 를 넣 어 주 십시오.
오래된 AF 방문 httpsDemo
새로운 AF httpsDemo 방문
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Swift의 패스트 패스Objective-C를 대체하기 위해 만들어졌지만 Xcode는 Objective-C 런타임 라이브러리를 사용하기 때문에 Swift와 함께 C, C++ 및 Objective-C를 컴파일할 수 있습니다. Xcode는 S...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.