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

Принцип аутентификации сертификата самоиспользования HTTPS и обертки запросов данных в iOS

Обзор: На конференции разработчиков WWDC 2016 компания Apple объявила о крайнем сроке: до 1 января 2017 года все приложения в App Store должны будут включить функцию безопасности App Transport Security. App Transport Security (ATS) - это функция защиты конфиденциальности, введенная Apple в iOS 9, которая блокирует загрузку ресурсов HTTP в открытом тексте и требует использования более безопасного HTTPS для подключения. В настоящее время Apple позволяет разработчикам временно отключать ATS и продолжать использовать подключения HTTP, но до конца года все приложения в официальных магазинах будут вынуждены использовать ATS.

В проекте используются фреймворки AFNetworking 3.0 и выше, из-за ATS iOS позволяет использовать только ссылки, начинающиеся с Https, до 30 декабря 2016 года Apple позволял обойти ATS, как показано на рисунке:

Но с 1 января 2017 года больше не будут принимать приложения, использующие 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;
}

2. Реализация методов Get и Post

При использовании сертификат, предоставленный сервером, нужно преобразовать в формат .cer и перетащить в корневую директорию проекта, затем привязать в методе. Например, имя сертификата, предоставленного сервером: Kuture.crt. После получения сертификата дважды щелкните по нему, чтобы установить, затем откройте ключевойchain, щелкните правой кнопкой по сертификату с именем 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) {
      //получение доверительного объекта сервера
      SecTrustRef serverTrust = [[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 = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
          return disposition;
            if (netWorkType == 0){
          }
        return disposition;
          //Отмена вызова
          disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
      return disposition;
        if (netWorkType == 0){
      }
      [_manager GET:api parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
    };
  }
  else if (netWorkType == 1){
    }
    }
      if (sucess){
        sucess(responseObject);
      }
        NSLog(@"Сбой подключения или отсутствует сеть");
      }
    failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
      fail(error);
    };
  [_manager POST:api parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
    success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
    }
      if (sucess){
        sucess(responseObject);
      }
        NSLog(@"Сбой подключения или отсутствует сеть");
      }
    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);
  }; Fail:^(NSError *error) {
    NSLog(@"Ошибка:%@",error);
  };

Вот и все, что есть в этой статье, надеюсь, это поможет вам в изучении. Также希望大家多多支持呐喊教程。

Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору. Контент предоставлен пользователями Интернета, загружен пользователями самостоятельно, сайт не имеет права собственности, не был отредактирован вручную и не несет ответственности за связанные с этим юридические вопросы. Если вы обнаружите подозрительное содержимое, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма замените # на @) для сообщения о нарушении авторских прав,并提供 соответствующие доказательства. Если подтвердится, сайт немедленно удалят подозрительное содержимое.

Основной курс
Рекомендуем к просмотру