在学习 Alamofire
的安全认证以前,咱们先来了解下 HTTPS
。swift
在 HTTP
协议中有可能存在信息窃听或者身份假装等安全问题,使用 HTTPS
通讯机制能够有效地防止这些问题。 HTTP
的不足:浏览器
HTTP
的请求和响应数据。HTTP
协议中没有加密机制,但经过 SSL
(Secure Socket Layer,安全套接层)或 TLS
(Transport Layer Security ,安全层传输协议)的组合使用,加密 HTTP
的通讯内容。 与 SSL
组合使用的 HTTP
被称为 HTTPS
(HTTP Secure,超文本传输安全协议)或 HTTP over SSL。安全
HTTPS = HTTP + 加密 + 认证 + 完整性保护服务器
HTTPS
并不是是应用层的一种新协议,只是 HTTP
通讯接口部分用 SSL
和 TLS
协议代替而已。一般 HTTP
直接跟 TCP
通讯,当使用 SSL
时,则变成先和 SSL
通讯,再由 SSL
和 TCP
通讯了。简言之,HTTPS
就是身披 SSL
协议这层外壳的 HTTP
。 微信
咱们经常使用的加密方式有共享密钥加密(对称加密)和公开密钥加密(非对称加密)两种。session
💡:在现代汉语里,“钥”读yào的,只出如今【钥匙】这个词里,“钥”居词首。其余都读yuè,且都出如今词尾。app
加密和解密同用一个秘钥的方式称为共享秘钥加密
(Common key crypto system),也称为对称秘钥加密
。学习
💡:这个很好理解,举个生活中常见的例子,你用钥匙把钱放保险柜里了,把钥匙给你媳妇了,你媳妇只有经过这把钥匙才能打开保险柜拿到钱。(钥匙就是秘钥,钱就是信息原文,装了钱的保险柜就是密文)网站
公开秘钥加密很好地解决了共享秘钥加密的困难。 它使用一堆非对称的秘钥,一把叫作私有密钥(private key),另外一把公开密钥(public key),顾名思义,私钥不能让其余任何人知道,而公钥则能够随意发布。ui
使用公开秘钥加密方式,发送密文的一方使用对方的公开密钥进行加密,对方收到被加密的信息后再用本身的私钥进行解密。这样就不用发送私钥了,也就不用担忧被窃听盗走私钥。若是想仅仅根据密文和公钥就恢复信息原文就目前的技术来看是不太现实的。
💡我想个例子帮助理解:腾讯发布了微信 app,全部人均可下载注册登陆,但只有腾讯有办法查到你的密码数据。别人就算拿了到你已经把微信登录成功的手机,他在 app 里也找不到你的密码(用手机验证重置密码也得不到旧密码数据)。这里微信软件注册登陆功能就是
公钥
,密码数据就是信息原文
,登陆之后的微信就是密文
,腾讯查询你密码数据的能力就是秘钥
。
SSL
采用的是公开密钥加密(Public-key cryptography),属于非对称加密。HTTPS
采用混合加密机制,就是共享秘钥加密和公开密钥加密二者并用的混合加密机制。
为何不全用公开密钥加密?由于与共享秘钥加密相比,处理起来更复杂、处理速度慢。因此 HTTPS
充分利用二者优点,在交换秘钥环节使用公开密钥加密方式,以后的简历通讯交换报文阶段则用时共享秘钥加密方式。
公开密钥加密方式仍然有一些问题,那就是没办法证实公钥自己是否是真的公钥,有可能在公钥传输中,真正的公钥已经被攻击者替换掉了。这时就须要使用数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书。 数字证书认证机构的业务流程:
数字证书的生成是分层级的,下一级的证书须要其上一级证书的私钥签名。因此后者是前者的证书颁发者,也就是说上一级证书的主题名是其下一级证书的签发者名。 例如打开咱们的 Safari 浏览器,在简书的网站能够看到网址前有一个🔐的标志,点一下选择显示证书。 发现简书的根证书是 DigiCert Global Root CA
:
二级证书是 DigiCert SHA2 Secure Server CA
:
最后的三级证书是 **.jianshu.com
:
Alamofire
请求的安全认证配置有这六种模式:
public enum ServerTrustPolicy {
case performDefaultEvaluation(validateHost: Bool)
case performRevokedEvaluation(validateHost: Bool, revocationFlags: CFOptionFlags)
case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
case disableEvaluation
case customEvaluation((_ serverTrust: SecTrust, _ host: String) -> Bool)
复制代码
.performDefaultEvaluation
默认策略,只有合法证书才能经过验证.performRevokedEvaluation
对注销证书作的一种额外设置.pinCertificates
证书验证模式,表明客户端会将服务器返回的证书和本地保存的证书中的 全部内容
所有进行校验,若是正确,才继续执行。.pinPublicKeys
公钥验证模式,表明客户端会将服务器返回的证书和本地保存的证书中的 PublicKey部分
进行校验,若是正确,才继续执行。.disableEvaluation
该选项下验证一直都是经过的,无条件信任。.customEvaluation
自定义验证,须要返回一个布尔类型的结果。最经常使用的有这三种: .pinCertificates
证书验证模式、.pinPublicKeys
公钥验证模式和 .disableEvaluation
不验证模式
pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
复制代码
- 参数1:
certificates
表明的是证书- 参数2:
validateCertificateChain
表明是否验证证书链- 参数3:
validateHost
表明是否验证子地址
能够看到 Alamofire
很是人性化,在 ServerTrustPolicy
枚举中还给咱们提供了下面的方法,帮咱们遍历查找出了项目主 bundle
中的证书:
public static func certificates(in bundle: Bundle = Bundle.main) -> [SecCertificate] {
var certificates: [SecCertificate] = []
let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in
bundle.paths(forResourcesOfType: fileExtension, inDirectory: nil)
}.joined())
for path in paths {
if
let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData,
let certificate = SecCertificateCreateWithData(nil, certificateData)
{
certificates.append(certificate)
}
}
return certificates
}
复制代码
certificates
传参的时候直接传 ServerTrustPolicy.certificates()
便可,若是你的证书是放在其余 bundle
中,也能够传参进去指定 bundle
。
最后使用证书模式验证完的整请求以下:
let serverTrustPlolicies:[String: ServerTrustPolicy] = [
hostUrl: .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true)
]
let sessionManger = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPlolicies))
sessionManager?.request(urlString).response { (defaultResponse) in
print(defaultResponse)
}
复制代码
若是采用公钥验证模式,则使用 .pinPublicKeys
这个枚举值,第一个参数传公钥,其余参数和证书验证模式同样:
case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
复制代码
第一个参数直接传递 Alamofire
提供给咱们的 ServerTrustPolicy.publicKeys()
方法便可。公钥验证模式的好处是,只要公钥不变,就能够一直使用,不用更新证书,不用担忧证书过时了。
若是采用公钥验证模式,则使用 .disableEvaluation
,这样就无论有没有证书,证书有没有效都采用非安全方式访问了。
以上的总结参考了并部分摘抄了如下文章,很是感谢如下做者的分享!:
一、上野 宣 的《图解https》
二、做者StanOz的《iOS 中对 HTTPS 证书链的验证》
转载请备注原文出处,不得用于商业传播——凡几多