Alamofire 学习--安全认证

1、HTTPS

在学习 Alamofire 的安全认证以前,咱们先来了解下 HTTPSswift

一、为何要用 HTTPS

HTTP 协议中有可能存在信息窃听或者身份假装等安全问题,使用 HTTPS 通讯机制能够有效地防止这些问题。 HTTP 的不足:浏览器

  • 通讯使用明文(不加密),内容可能会被窃听。
  • 不验证通讯方的身份,所以有可能遭遇假装
  • 我发证实报文的完整性,因此有可能已遭篡改 像咱们平时经常使用的抓包软件 Wireshark、Charles 等均可以轻松抓取到 HTTP 的请求和响应数据。

HTTP 协议中没有加密机制,但经过 SSLSecure Socket Layer,安全套接层)或 TLSTransport Layer Security ,安全层传输协议)的组合使用,加密 HTTP 的通讯内容。 与 SSL 组合使用的 HTTP 被称为 HTTPSHTTP Secure,超文本传输安全协议)或 HTTP over SSL安全

HTTPS = HTTP + 加密 + 认证 + 完整性保护服务器

HTTPS 并不是是应用层的一种新协议,只是 HTTP 通讯接口部分用 SSLTLS 协议代替而已。一般 HTTP 直接跟 TCP 通讯,当使用 SSL 时,则变成先和 SSL 通讯,再由 SSLTCP 通讯了。简言之,HTTPS 就是身披 SSL 协议这层外壳的 HTTP微信

二、加密技术

咱们经常使用的加密方式有共享密钥加密(对称加密)和公开密钥加密(非对称加密)两种。session

💡:在现代汉语里,“钥”读yào的,只出如今【钥匙】这个词里,“钥”居词首。其余都读yuè,且都出如今词尾。app

一、共享秘钥加密

加密和解密同用一个秘钥的方式称为共享秘钥加密Common key crypto system),也称为对称秘钥加密学习

💡:这个很好理解,举个生活中常见的例子,你用钥匙把钱放保险柜里了,把钥匙给你媳妇了,你媳妇只有经过这把钥匙才能打开保险柜拿到钱。(钥匙就是秘钥,钱就是信息原文,装了钱的保险柜就是密文)网站

  • 秘钥发送问题: 以共享秘钥方式加密时必须将秘钥也发给对方,但在互联网上转发秘钥时就有被窃听的风险,不发送对方就不能解密,若是秘钥都安全送达了,那数据也应该能安全送达了。另外还得设法安全的保管接收到的秘钥。

二、公开秘钥加密

公开秘钥加密很好地解决了共享秘钥加密的困难。 它使用一堆非对称的秘钥,一把叫作私有密钥(private key),另外一把公开密钥(public key),顾名思义,私钥不能让其余任何人知道,而公钥则能够随意发布。ui

使用公开秘钥加密方式,发送密文的一方使用对方的公开密钥进行加密,对方收到被加密的信息后再用本身的私钥进行解密。这样就不用发送私钥了,也就不用担忧被窃听盗走私钥。若是想仅仅根据密文和公钥就恢复信息原文就目前的技术来看是不太现实的。

💡我想个例子帮助理解:腾讯发布了微信 app,全部人均可下载注册登陆,但只有腾讯有办法查到你的密码数据。别人就算拿了到你已经把微信登录成功的手机,他在 app 里也找不到你的密码(用手机验证重置密码也得不到旧密码数据)。这里微信软件注册登陆功能就是公钥,密码数据就是信息原文,登陆之后的微信就是密文,腾讯查询你密码数据的能力就是秘钥

三、HTTPS 混合加密机制

SSL 采用的是公开密钥加密(Public-key cryptography),属于非对称加密。HTTPS 采用混合加密机制,就是共享秘钥加密和公开密钥加密二者并用的混合加密机制。

为何不全用公开密钥加密?由于与共享秘钥加密相比,处理起来更复杂、处理速度慢。因此 HTTPS 充分利用二者优点,在交换秘钥环节使用公开密钥加密方式,以后的简历通讯交换报文阶段则用时共享秘钥加密方式。

三、证实公钥正确性的证书

公开密钥加密方式仍然有一些问题,那就是没办法证实公钥自己是否是真的公钥,有可能在公钥传输中,真正的公钥已经被攻击者替换掉了。这时就须要使用数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书。 数字证书认证机构的业务流程:

数字证书的生成是分层级的,下一级的证书须要其上一级证书的私钥签名。因此后者是前者的证书颁发者,也就是说上一级证书的主题名是其下一级证书的签发者名。 例如打开咱们的 Safari 浏览器,在简书的网站能够看到网址前有一个🔐的标志,点一下选择显示证书。 发现简书的根证书是 DigiCert Global Root CA

二级证书是 DigiCert SHA2 Secure Server CA

最后的三级证书是 **.jianshu.com

2、Alamofire 中的安全认证

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 证书链的验证》

转载请备注原文出处,不得用于商业传播——凡几多

相关文章
相关标签/搜索