AFNetworking的安全策略
上面我们说到,AFNetworking3.x是对NSURLSession的一层包装,包括delegate的实现和回调,还有请求接口的包装。不过这只是一部分基本功能,实际上还有一些同样很复杂并且重要的部分。比如现在我们看到的就是其中的安全策略。
本质上AFNetworking的安全策略是根据https来完成的。先简单讲讲https和http的差别:
由于超文本传输协议http协议以明文的方法传送内容,不提供任何数据加密,所以很容易被攻击者截取到http传输的内容,在这个基础上,开发了新的https协议,即加入了SSL安全套接字方法,依靠证书来验证服务器的身份,这样在普通http传输的过程中传输的信息就是经过了证书加密之后的数据,提高了安全性。
简单总结一下就是:
- 用户发起请求,服务器响应并返回一个证书,包括基本信息和公钥
- 用户拿到证书之后验证是否合法
- 生成一个随机数作为加密的密钥,然后用先前服务器所给的密钥来加密,并返回给服务器
- 服务器用密钥解密这个随机数,然后再用解密之后的随机数把需要返回的数据来加密并返回给用户
- 终于用户拿到加密的数据,用最开始的随机数来解密,完成了数据的交接
这是一个单步认证,实际上服务器也会对用户端传过来的信息进行验证,过程是差不多的。本质上还是使用一个随机数和一个公钥进行加密和解密,并不难理解。
AFURLSessionManager中完成的一个delegate方法实现了https认证的过程:
上述就是如何应对challenge的方法,总结一下基本功能(1)指定https为默认的认证方法 (2)如果自定义了处理challenge的block self.taskDidReceiveAuthenticationChallenge那么就直接调用,并给credential赋值,最后交给completionHandler进行认证 (3)如果没有自定义block,就根据是否认证方法为NSURLAuthenticationMethodServerTrust来判断是否实现这个单向认证。 (4)如果是直接信任服务器端则创建证书。
需要说明的是,(3)(4)之间还有一个查看securityPolicy的过程,如果被认证符合安全策略才会允许生成证书(证书通过serverTrust中包含的服务器证书认证信息),这样在底层系统验证证书合法性之前就可以先做一道验证,把应该取消的https过程给取消掉。
先看看securityPolicy的内容吧:
|
|
SSLPinningMode是securytyPolicy的一个重要属性,记录https验证模式,有三种验证方式
|
|
刚才调用的验证安全性的方法为:
|
|
上面就是securityPolicy的核心部分,重要内容都标上了注释。总结来讲就是根据三种模式来进行证书的验证:(1)如果是AFSSLPinningModeNone,肯定返回yes(根据是否需要验证和是否自签有些差别) (2)如果是AFSSLPinningModeCertificate,那么从serverTrust中获取证书然后和本地的证书集合去匹配 (3)如果是AFSSLPinningModePublicKey,那么从serverTrust中去获取公钥然后和本地的公钥进行配对。
其实过程非常清晰,不过细节上调用了很多原生的security代码,从代码角度需要更详细地了解。
AFNetworking包装了一系列系统函数在上面的方法中调用,现在可以看看其中重要的几个方法的实现。
验证servetTrust的函数:
|
|
首先说说
第一个函数获取证书链,内容很简单,先获取serverTrust中的证书个数,然后依次将证书对象转化成NSData并加入到trustChain中。
第二个函数获取公钥,稍微复杂一点,在上面一个函数取出所有证书的基础上,加入了认证和从证书链中提取公钥的过程。
总结来讲,基本上如果用户用的不是自签名的证书,那么基本什么都不用管,直接用AFNetworkign就能够完成(大部分情况)。如果自签名就需要设置policy,尽量不要用到吧…
AFNetworking总体而言能在系统底层之前就验证证书,提高了效率。
补充证书和证书链
可能上面说的证书,证书链等东西有些抽象,具体补充一下相关的信息:
数字证书的生成是分层级的,下一级的证书需要其上一级证书的私钥签名。
所以后者是前者的证书颁发者,也就是说上一级证书的 Subject Name 是其下一级证书的 Issuer Name。所以也就存在了我们上面数说的证书的根节点和叶子节点这么一说。
关于根证书:
数字证书认证机构(Certificate Authority, CA)签署和管理的 CA 根证书,会被纳入到你的浏览器和操作系统的可信证书列表中,并由这个列表判断根证书是否可信。也就是根证书是约定好的,不需要其他的数字证书的私钥进行签名。
在iOS上对证书的验证:
信任链中如果只含有有效证书并且以可信锚点(trusted anchor)结尾,那么这个证书就被认为是有效的。一般情况下信任锚点是系统隐式信任的证书,比如CA根节点,但是也可以在验证证书链的时候设置自签名的证书作为信任锚点(上面说到的自签名的验证中有提到)