iOS安全策略之HTTPS

1.HTTPS传输流程

2.常用加密算法

3.AFN证书校验策略及核心方法

4.SSL Pinning

5.CA证书申请流程


HTTPS经由超文本传输协议进行通信,但利用SSL/TLS来对数据包进行加密。HTTPS开发的主要目的,是提供对网络服务器的身份认证,保护交换数据的隐私与完整性

1.HTTPS传输流程

HTTPS传输流程.png

由于不相信服务器生成的随机数,所以需要客户端生成pre-master-securet,然后再由服务端加密,最后得到master-securet(主密钥),建立密道通信。(减少被猜中的可能)

2.常用加密算法

非对称加密算法:RSA,DSA/DSS
对称加密算法:AES,RC4,3DES
HASH算法:MD5,SHA1,SHA256

非对称加密算法用于握手过程中的加密生成的密码,
对称加密算法用于对真正传输的数据进行加密,
HASH算法用于验证数据的完整性,是否被篡改等

非对称加密生成密码是整个加密过程的关键,非对称加密会生成公钥和私钥,
公钥负责数据加密,(可以随意传输)
私钥负责解密,(重中之重)

3.AFN证书校验策略及核心方法

NSURLSession 封装了HTTPS链接的建立加密解密功能,但并没有验证证书的合法性,无法避免中间人攻击,要真正的安全通讯,需要我们手动去验证证书,

客户端校验策略

 sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];  

 * AFSSLPinningModeNone 不做SSL pinning 只信任证书颁发机构证书,自己生成证书不通过
 * AFSSLPinningModeCertificate 客户端保存证书拷贝 第一步验证证书的域名/有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。
 * AFSSLPinningModePublicKey   客户端保存证书拷贝 只是验证时只验证证书里的公钥,不验证证书的有效期等信息

核心证书校验方法

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(NSString *)domain
{
 
  **** AFSSLPinningModeNone 不做SSL Pinning  当需要使用证书验证域名时,需要使用AFSSLPinningModePublicKey或AFSSLPinningModeCertificate
 
  if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {

 // According to the docs, you should only trust your provided certs for evaluation.
  Pinned certificates are added to the trust. Without pinned certificates,
  there is nothing to evaluate against.

  From Apple Docs:
          "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
           Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
return NO;
  }
  
  NSMutableArray *policies = [NSMutableArray array];
  **** 需要验证域名时,添加一个域名验证策略
  if (self.validatesDomainName) {
    [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
  } else {
    [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
  }
  **** 设置验证策略
  SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
  
  if (self.SSLPinningMode == AFSSLPinningModeNone) {
   **** AFSSLPinningModeNone 时,allowInvalidCertificates为YES ,则代表服务器任何证书都能验证
   **** 如果是NO,则需要判断此服务器是否是系统信任证书

return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
  } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
 
   **** 如果服务器证书不是系统信任证书,且不允许不信任证书通过验证则返回NO
    return NO;
  }
  
  switch (self.SSLPinningMode) {
    case AFSSLPinningModeNone:
    default:
      return NO;
    case AFSSLPinningModeCertificate: {
 
 **** AFSSLPinningModeCertificate 是直接将本地证书设置为信任的根证书,然后来进行判断,并且比较本地证书内容和服务器证书内容是否一致,如果有一个相同则返回YES

  NSMutableArray *pinnedCertificates = [NSMutableArray array];
  for (NSData *certificateData in self.pinnedCertificates) {
    [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
  }
 
 **** 设置本地证书为根证书
      SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
 
 **** 通过本地证书来判断服务器证书是否可信,不可信则不通过
      if (!AFServerTrustIsValid(serverTrust)) {
        return NO;
      }
  
  // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
  NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
  ****  判断本地证书和服务器证书是否相同
  for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
    if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
      return YES;
    }
  }
  
  return NO;
}
case AFSSLPinningModePublicKey: {
  NSUInteger trustedPublicKeyCount = 0;
  NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
  **** AFSSLPinningModePublicKey 是通过比较证书中公钥部分来进行校验。通过SecTrustCopyPublicKey方法获取本地证书和服务器证书,进行比较,如果有一个相同则验证通过

  for (id trustChainPublicKey in publicKeys) {
    for (id pinnedPublicKey in self.pinnedPublicKeys) {
      if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
        trustedPublicKeyCount += 1;
      }
    }
  }
  return trustedPublicKeyCount > 0;
}
}
    return NO;
}

4.SSL Pinning

SSL Pinning
SSL Pinning 即证书绑定,客户端直接保存服务端证书,建立HTTPS连接时会校验服务端返回证书和客户端证书是否一致,一致则不再去信任证书机构里验证。

SSL Pinning 为什么安全

其实如果中间人从客户端取出证书(公钥),并使用证书冒充服务器与客户端进行通信时,也可以通过证书验证,但后续流程走不下去,因为客户端会用公钥加密,中间人从客户端截取的证书是公钥,缺少对应私钥即使截获了信息也无法解密。所以能够最大程度保护信息安全

PS: 从上面的通信过程中,最重要的是存储在服务器的私钥。因为只有私钥生成了在通信过程中传递的证书(公钥),且只有通过私钥才能对公钥加密的信息进行解密,所以在开发过程中保护好私钥的安全。

什么时候使用SSL Pinning

如果证书是从受信任的CA机构颁布的,验证是没有问题的,如果是自己颁发证书,无法通过系统受信任的CA机构列表验证证书时,需要通过SSL Pinnig的方式来验证

如何使用SSL Pinning

1.将.cer 证书放进工程中
2.设置securityPolicy证书校验策略

 #pragma mark - SecurityPolicy
+ (void)securityPolicy:(AFHTTPSessionManager *)sessionManager{
  
  sessionManager.securityPolicy = [AFSecurityPolicy defaultPolicy];
  sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    /** allowInvalidCertificates 是否允许不信任的证书(证书无效、证书时间过期)通过验证 ,默认为NO */
  [sessionManager.securityPolicy setAllowInvalidCertificates:NO];
  
  /** validatesDomainName 是否验证域名证书的CN(common name)字段 默认YES*/
  sessionManager.securityPolicy.validatesDomainName = YES;
  
  /** NSSet<NSData*> *pinnedCertificates 根据验证模式来返回用于验证服务器的证书。*/
  NSString *cerPath  = [[NSBundle mainBundle] pathForResource:@"XXXX" ofType:@"cer"];
  NSData *certData = [NSData dataWithContentsOfFile:cerPath];
  [sessionManager.securityPolicy setPinnedCertificates:[NSSet setWithArray:@[certData]]];
  
  
}
iOS设备已有哪些CA证书

每个版本的iOS设备中,都会包含一些既有的CA根证书。如果接收到的证书是iOS信任的CA根证书签名的,那么则为合法证书;否则则为“非法”证书
iOS已有的CA根证书:https://support.apple.com/en-us/HT204132

5.CA证书申请流程

证书流程1.jpg
证书流程2.jpg

补充:SSL 与 TLS 协议

SSL协议(传输层安全协议)工作方式:客户端要收发几个握手信号:
1.发送一个“ClientHello”消息。内容包括支持的协议版本,比如TLS1.0版
2.收到一个“ServerHello”消息。内容包括支持的协议版本,
3.客户端与服务端交换证书。(依靠被选择的公钥系统)
4.服务端请求客户端公钥。客户端有证书即双向身份认证,没证书时随机生成公钥
5.客户端与服务端通过公钥保密协议共同的主私钥(伪随机数)

在SSL 3.0中发现设计缺陷后,SSL 被禁用,之后 ETF将SSL标准化,即 RFC 2246 ,并将其称为TLS(Transport Layer Security),即TLS 1.0
TLS 1.0包括可以降级到SSL 3.0的实现,这削弱了连接的安全性
TLS 1.1 添加对CBC攻击的保护:隐式IV被替换成一个显式的IV。更改分组密码模式中的填充错误。支持IANA登记的参数。
TLS 1.2 可使用密码组合选项指定伪随机函数使用SHA-256替换MD5-SHA-1组合。AES加密的支持
TLS 1.3 草案 2016年1月

相关链接:
http://www.jianshu.com/p/668b263befc8
https://runningyoung.github.io/2016/05/16/2016-05-16-HTTPS/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容