English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

iOS에서 Https 자신 서명 인증 및 데이터 요청의 캡슐화 원리

요약: WWDC 2016개발자 회의에서 Apple이 발표한 마지막 일정입니다:2017년1월1일 App Store에 있는 모든 애플리케이션은 App Transport Security(ATS) 기능을 활성화해야 합니다. App Transport Security(ATS)는 Apple이 iOS 9에 포함된隐私保护功能,屏蔽明文HTTP资源加载,连接必须经过更安全的HTTPS。Apple은 현재 개발자가 ATS를 일시적으로关闭할 수 있도록 허용하고 있으며, HTTP 연결을 계속 사용할 수 있습니다. 그러나 연말까지 모든 공식 스토어 애플리케이션은 ATS를 강제로 사용해야 합니다.

프로젝트에서 사용하는 프레임워크는 AFNetworking입니다. 3.0 이상 버전에서 ATS의 이유로 iOS는 Https로 시작하는 링크만 사용할 수 있으며2016년12월30일 이전, Apple은 ATS를 우회할 수 있도록 허용했습니다. 다음 그림과 같이:

하지만2017년1월1月开始,http를 통해 자원을 로드하는 애플리케이션은 더 이상 받아들여지지 않기 때문에, 이 글은 AFN을 사용하여 자신의 서명된 인증서를 인증하는 방법에 대해 설명합니다. (주의: CA 기관 인증서를 사용하는 경우 인증을 하지 않아도 됩니다.Https로 시작하는 링크를 통해 데이터 접근 및 페이지 로드를 할 수 있습니다.) 프로젝트는 GitHub에 업로드되었습니다. (소스 코드를 참고하고 싶다면 링크를 클릭하세요):HttpsSignatureCertificate_jb51.rar

1، 기본 클래스를 만들어 이를 AKNetPackegeAFN으로 명명

 1>  .h 파일, 필요한 Get 및 Post 메서드를 생성

#import <Foundation/Foundation.h>
typedef enum{
  AKNetWorkGET ,  /**< GET 요청 */
  AKNetWorkPOST = 1 /**< POST 요청 */
}AKNetWorkType;
typedef void (^HttpSuccess)(id json);
typedef void (^HttpErro)(NSError* error);
@interface AKNetPackegeAFN : NSObject
+(instancetype)shareHttpManager;
/*
 *
 netWorkType: 요청 방식 GET 또는 POST
 signature: 인증서 사용 여부, 사용하면 인증서 이름을 직접 입력, 사용하지 않으면 nil을 입력
 api: 요청의 URL 인터페이스
 parameters: 요청 파라미터
 sucess: 요청 성공 시의 반환 값
 fail: 요청 실패 시의 반환 값
 *
 */
- (void)netWorkType:(AKNetWorkType)netWorkType Signature:(NSString *)signature API:(NSString *)api Parameters:(NSDictionary *)parameters Success:(HttpSuccess)sucess Fail:(HttpErro)fail;
@end

2> .m 파일, 헤더 파일 AFNetworking.h를 가져와 Manager 속성을 생성하고 shareHttpManager 클래스 메서드를 구현합니다

#import "AKNetPackegeAFN.h"
#import "AFNetworking.h"
@interface AKNetPackegeAFN()
@property (nonatomic,strong) AFHTTPSessionManager *manager;
@end
@implementation AKNetPackegeAFN
+(instancetype)shareHttpManager{
  static dispatch_once_t onece = 0;
  static AKNetPackegeAFN *httpManager = nil;
  dispatch_once(&onece, ^(void){
    httpManager = [[self alloc]init];
  });
  return httpManager;
}

2Get과 Post 메서드 구현

사용 시 백그라운드에서 제공된 인증서를 .cer 형식으로 변환하여 프로젝트 루트 디렉토리에 드래그 앤 드롭하여 메서드에서 바인딩할 수 있습니다. 예를 들어, 백그라운드에서 제공된 인증서 이름: Kuture.crt. 인증서를 받은 후 더블 클릭하여 설치하고, 키 체인을 엽니다. Kuture 이름의 인증서를 오른쪽 클릭하여 .cer 확장자를 선택하고, 확인을 누르면 됩니다. 아래와 같이 보입니다:

  -->     -->

-->

GET과 POST 구현 메서드의 감싸기

- (void)netWorkType:(AKNetWorkType)netWorkType Signature:(NSString *)signature API:(NSString *)api Parameters:(NSDictionary *)parameters Success:(HttpSuccess)sucess Fail:(HttpErro)fail{
  //예약서버 검증 모드를 시작합니다
  AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
  //자신서명 증명서를 사용할 수 있는가
  signature == nil ? (void)(securityPolicy.allowInvalidCertificates = NO):(securityPolicy.allowInvalidCertificates = YES);
  //도메인 이름을 검증해야 하는가
  securityPolicy.validatesDomainName = NO;
  _manager = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:api]];
  _manager.responseSerializer = [AFJSONResponseSerializer serializer];
  _manager.securityPolicy = securityPolicy;
  _manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"application/xml",@"text/xml",@"text/json",@"text/plain",@"text/javascript",@"text/html", nil];
  if (signature != nil){
    __weak typeof(self) weakSelf = self;
    [_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {
      //서버의 trust object를 가져오기
      SecTrustRef 서버Trust = [[challenge protectionSpace] serverTrust];
      //자신의 서명 인증서에서 가져옵니다
      NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"你的证书名字" ofType:@"cer"];
      NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
      if (!cerData) {
        NSLog(@"==== .cer 파일이 nil입니다 ====");
        return 0;
      }
      NSArray *cerArray = @[cerData];
      weakSelf.manager.securityPolicy.pinnedCertificates = cerArray;
      SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)cerData);
      NSCAssert(caRef != nil, @"caRef is nil");
      NSArray *caArray = @[(__bridge id)(caRef)];
      NSCAssert(caArray != nil, @"caArray is nil");
      //읽어들인 인증서를 serverTrust의 루트 인증서로 설정합니다
      OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
      SecTrustSetAnchorCertificatesOnly(serverTrust, NO);
      NSCAssert(errSecSuccess == status, @"SectrustSetAnchorCertificates failed");
      //질문 인증 방식 선택 처리 방식
      NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
      __autoreleasing NSURLCredential *credential = nil;
      //NSURLAuthenTicationMethodServerTrust질문 인증 방식
      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 {
        disposition = NSURLSessionAuthChallengePerformDefaultHandling;
      }
      return disposition;
    }
  }
  if (netWorkType == 0){
    [_manager GET:api parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
    } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
      if (sucess){
        sucess(responseObject);
      else{
        failure:^(NSURLSessionDataTask
      }
    } * _Nullable task, NSError * _Nonnull error) {
      fail(error);
    }
  }else if (netWorkType == 1){
    [_manager POST:api parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
    } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
      if (sucess){
        sucess(responseObject);
      else{
        failure:^(NSURLSessionDataTask
      }
    } * _Nullable task, NSError * _Nonnull error) {
      fail(error);
    }
  }  
}

2  사용 방법은, 데이터를 가져오거나 전달해야 하는 클래스 안에서 AKNetPackegeAFN.h 헤더 파일을 직접 가져오고 메서드를 구현하는 것입니다. 예를 들어:

//객체 생성
  //자신의 인증서를 사용할 경우, AKNetPackegeAFN의 메서드에 인증서를 바인딩하려면 먼저 프로젝트에 인증서를 드래그 앤 드롭하여 추가해야 합니다.
  /*
   *
   netWorkType: 요청 방식 GET 또는 POST
   signature: 인증서 사용 여부, 사용하면 인증서 이름을 직접 입력, 사용하지 않으면 nil을 입력
   api: 요청의 URL 인터페이스
   parameters: 요청 파라미터
   sucess: 요청 성공 시의 반환 값
   fail: 요청 실패 시의 반환 값
   *
   */
  AKNetPackegeAFN *netHttps = [AKNetPackegeAFN shareHttpManager];
  [netHttps netWorkType: 요청 유형 Signature: 인증 이름 API: 요청 URL Parameters: 파라미터 Success:^(id json) {
    NSLog(@"Json:%@", json);
  } *error) {
    NSLog(@"오류:%@", error);
  }

이것이 본 문서의 모든 내용입니다. 많은 도움이 되길 바라며, 나아가 각오를 다해 노래 교본을 지지해 주시기 바랍니다.

고지사항: 본 문서의 내용은 인터넷에서 가져왔으며, 원작자의 소유물입니다. 인터넷 사용자가 자발적으로 기여하고 업로드한 내용으로, 이 사이트는 소유권을 가지지 않으며, 인공적인 편집 처리를 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 침해가 의심되는 내용을 발견하면 notice#w 이메일로 알려주시기 바랍니다.3codebox.com에 대한 신고를 위해 이메일을 보내시면, #을 @으로 변경하십시오. 관련 증거를 제공하시면, 사실을 확인하면 즉시 저작권 침해 내용을 삭제할 것입니다.