前几日,项目组出于安全角度的考虑,要求项目中的请求使用https请求,因为是企业内部使用的app,因此使用了自签名的证书,而自签名的证书是不受信任的,所以我们就需要自己来做证书的验证,包括服务器验证客户端的证书和我们要信任服务器的证书,SSL双向认证的原理我这里就不赘述了,这里提供两篇博客

    iOS安全系列之一:HTTPS: http://oncenote.com/2014/10/21/Security-1-HTTPS/

    iOS安全系列之二:HTTPS进阶: http://oncenote.com/2015/09/16/Security-2-HTTPS2/

从开始准备到调试成功一共用了两天,查阅了很多网上提供的解决办法,最后发现很多解决办法都缺少了一个很重要的过程,就是将客户端的证书发送到服务器,让服务器验证我们的身份.如果没有这一步,那么我们的请求就会直接被服务器拒绝导致请求失败.

  话不多说,相信说多了也没人看..[手动滑稽]直接上代码,我这里用了afn3.0

  准备工作:

    首先要导入两个证书, 是两个  一个是客户端使用的.p12的证书,另外一个是服务器端的.cer的证书,将这两个证书拖入工程中,注意要添加target

    然后要配置ATS,ATS的配置我也提供一篇博客

    iOS 10 适配 ATS: http://www.jianshu.com/p/36ddc5b009a7

新建一个类,继承AFHTTPSessionManager, 我这里重写了initWithURL

  1. 1 - (instancetype)initWithBaseURL:(NSURL *)url {
  2. 2 self = [super initWithBaseURL:url];
  3. 3 if (self) {
  4. 4
  5. 5 self.requestSerializer.timeoutInterval = 25;
  6. 6 [self.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
  7. 7 [self.requestSerializer setValue:url.absoluteString forHTTPHeaderField:@"Referer"];
  8. 8
  9. 9 self.securityPolicy = [self getFreeCustomSecurityPolicy];
  10. 10
  11. 11 self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"text/html", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", nil];
  12. 12 self.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
  13. 13
  14. 14 [self setSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) {
  15. 15 NSLog(@"setSessionDidBecomeInvalidBlock error : %@",error);
  16. 16 }];
  17. 17 if ([url.absoluteString hasPrefix:@"https"]) {//当请求是https时,我们就需要做
  18. 18 __weak typeof(self) weakSelf = self;
  19. 19 [self setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing _Nullable * _Nullable credential) {
  20. 20 NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  21. 21 __autoreleasing NSURLCredential * credentialSelf =nil;
  22. 22 if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {//如果有受信任的证书,如果是自签名的证书,这里会是NSURLAuthenticationMethodClientCertificate
  23.  
  24. 23 if([weakSelf.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
  1. 24 credentialSelf = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
  2. 25 if(credentialSelf) {
  3. 26 disposition = NSURLSessionAuthChallengeUseCredential;
  4. 27 } else {
  5. 28 disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  6. 29 }
  7. 30 } else {
  8. 31 disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
  9. 32 }
  10. 33 } else {//当接收到的是NSURLAuthenticationMethodClientCertificate,我们就将我们的证书发送给服务器让其验证我们的身份
  11. 34 // client authentication
  12. 35 SecIdentityRef identity = NULL;
  13. 36 SecTrustRef trust = NULL;
  14. 37 NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"p12"];
  15. 38 NSFileManager *fileManager =[NSFileManager defaultManager];
  16. 39 if(![fileManager fileExistsAtPath:p12])
  17. 40 {
  18. 41 NSLog(@"client.p12:not exist");
  19. 42 } else {
  20. 43 NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];
  21. 44
  22. 45 if ([weakSelf extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data])
  23. 46 {
  24. 47 SecCertificateRef certificate = NULL;
  25. 48 SecIdentityCopyCertificate(identity, &certificate);
  26. 49 const void*certs[] = {certificate};
  27. 50 CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);
  28. 51 credentialSelf =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
  29. 52 disposition = NSURLSessionAuthChallengeUseCredential;
  30. 53 }
  31. 54 }
  32. 55 }
  33. 56 *credential = credentialSelf;
  34. 57 return disposition;
  35. 58 }];
  36. 59 }
  37. 60 }
  38. 61 return self;
  39. 62 }
  40. 63 - (BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
  41. 64 OSStatus securityError = errSecSuccess;
  42. 65 //client certificate password
  43. 66 NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"password" forKey:(__bridge id)kSecImportExportPassphrase];
  44. 67 CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
  45. 68 securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
  46. 69
  47. 70 if(securityError == 0) {
  48. 71 CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0);
  49. 72 const void*tempIdentity =NULL;
  50. 73 tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity);
  51. 74 *outIdentity = (SecIdentityRef)tempIdentity;
  52. 75 const void*tempTrust =NULL;
  53. 76 tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);
  54. 77 *outTrust = (SecTrustRef)tempTrust;
  55. 78 } else {
  56. 79 NSLog(@"Failedwith error code %d",(int)securityError);
  57. 80 return NO;
  58. 81 }
  59. 82 return YES;
  60. 83 }
  61. 84 - (AFSecurityPolicy *)getFreeCustomSecurityPolicy {
  62. 85 AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
  63. 86 NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
  64. 87 NSData *certData = [NSData dataWithContentsOfFile:cerPath];
  65. 88 NSSet *certificateSet = [[NSSet alloc] initWithObjects:certData, nil];
  66. 89 [securityPolicy setAllowInvalidCertificates:YES];
  67. 90 [securityPolicy setPinnedCertificates:certificateSet];
  68. 91 [securityPolicy setValidatesDomainName:NO];
  69. 92
  70. 93 return securityPolicy;
  71. 94 }

这样设置好了之后就可以发送使用自签名证书的https请求了 

希望可以帮助到遇到自签名证书无法发送请求的同学

代码不太优雅,轻喷,如有错误的地方欢迎指正

邮箱:masterLiPeng@163.com

AFNetWorking3.0使用 自签名证书的https请求的更多相关文章

  1. iOS 用自签名证书实现 HTTPS 请求的原理

    在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求.默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info ...

  2. iOS使用自签名证书实现HTTPS请求

    概述 在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求. 默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向 ...

  3. 超级简单的retrofit使用自签名证书进行HTTPS请求的教程

    1. 前言 HTTPS越来越成为主流,谷歌从 2017 年起,Chrome 浏览器将也会把采用 HTTP 协议的网站标记为「不安全」网站:苹果从 2017 年 iOS App 将强制使用 HTTPS: ...

  4. SpringBoot服务间使用自签名证书实现https双向认证

    SpringBoot服务间使用自签名证书实现https双向认证 以服务server-one和server-two之间使用RestTemplate以https调用为例 一.生成密钥 需要生成server ...

  5. curl wget 不验证证书进行https请求【转】

    $ wget 'https://x.x.x.x/get_ips' --no-check-certificate $ curl 'https://x.x.x.x/get_ips' -k 转自 curl ...

  6. 生成自签名证书-开启https

    1.生成CA证书 # 生成 CA 私钥 openssl genrsa -out ca.key 2048 # X.509 Certificate Signing Request (CSR) Manage ...

  7. iOS 的三种自建证书方法https请求相关配置

    如果你的app服务端安装的是SLL颁发的CA,可以使用系统方法直接实现信任SSL证书,关于Apple对SSL证书的要求请参考:苹果官方文档CertKeyTrustProgGuide 这种方式不需要在B ...

  8. Android 7.0解决抓取不到https请求的问题

    问题:Android7.0系统,使用fiddler不能抓取https请求 解决方法:  1.在源码res目录下新建xml目录,增加network_security_config.xml文件 (工程名/ ...

  9. tomcat使用自签名证书实现https加密访问

    部署好java环境和tomcat之后 执行以下语句 #生成证书,keytool是java工具命令,-genkey生成证书,-alias证书名称,-keyalg应该是指算法,-keystore是证书存储 ...

随机推荐

  1. UML和模式应用

    引言 Applying UML and Patterns,以一个商店POS系统NextGen和一个掷骰子游戏Monopoly为例,围绕OOA/D的基本原则GRASP,以迭代作为基本方法.以UML为表达 ...

  2. Java正则表达式之语法规则

    正则表达式是一种强大而灵活的文本处理工具,使用正则表达式能够以编程的方式,构造复杂的文本模式,并对输入的字符串进行搜索.一旦找到了匹配这些模式的部分,就能够随心所欲地它们进行处理.正则表达式提供了一种 ...

  3. OpenGL ES之GLSurfaceView学习一:介绍

    原文地址::http://120.132.134.205/cmdn/supesite/?uid-5358-action-viewspace-itemid-6527 GLSurfaceView是一个视图 ...

  4. MySQL与Oracle 差异比较之一数据类型

    数据类型 编号 ORACLE MYSQL 注释 1 NUMBER int / DECIMAL DECIMAL就是NUMBER(10,2)这样的结构INT就是是NUMBER(10),表示整型:MYSQL ...

  5. JSONP实例

    JSONP实例 package sus.app; import java.io.IOException; import java.util.Map; import javax.servlet.http ...

  6. [禅悟人生]"执著"是自缚的茧

    宋代苏东坡和佛印禅师是好朋友,他们习惯拿对方开玩笑.有一天,苏东坡到金山寺和佛印禅师打坐参禅,苏东坡觉得身心通畅,于是问禅师道:“禅师!你看我坐的样子怎么样?” “好庄严,像一尊佛!” 苏东坡听了非常 ...

  7. ylbtech-QQ(腾讯)-群

    ylbtech-DatabaseDesgin:ylbtech-QQ(腾讯)-Account-账户模块, Role-角色.权限模块, Message-消息模块, Qzone-QQ空间,Contacts- ...

  8. MySql通用分页存储过程

    MySql通用分页存储过程 1MySql通用分页存储过程 2 3过程参数 4p_cloumns varchar(500),p_tables varchar(100),p_where varchar(4 ...

  9. zzzzz

    Extension Method: Return another string if string is null or emptyJust a tiny little extension metho ...

  10. OS X中如何获取当前运行程序的路径

    OS X的执行程序一般分为两种.一种是控制台程序,一种是带有GUI的OS X应用程序. 控制台程序往往就一个文件构成executable,而GUI应用通常是一个包(即文件夹),里面除了executab ...