基于Alamofire 5.0.0 分析网络的安全认证。同时介绍一些 HTTP 与 HTTPS 的一些相关知识
HTTP 特性
- 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
- 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
- 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有 GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
- 灵活:HTTP 允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type 是 HTTP包 中用来表示内容类型的标识)加以标记。
HTTP 存在的问题
1.安全性差
2.每次请求传输结束,重新请求又要建立连接
3.后续处理之前信息必须重传,损耗性能
加密算法
1.对成加密
在对称加密当中加密使用的秘钥和解密使用的秘钥是相同的。也就是加密和解密都是同一个秘钥。这样秘钥的安全性就非常重要,秘钥是一定不能公开的
存在的缺点:对称加密的缺点就在于如果秘钥要是泄露,这样Client与Server之间的信息传递就不安全了。
2. 非对成加密
有一对秘钥叫做公钥与私钥,公钥是对外公开的,所有人都能拥有,但是私钥有且只有一个。公钥和私钥都能进行加密,但是公钥加密的密文只有私钥能够解密,私钥加密的所有公钥都能解密,这就是非对称加密。
缺点: 非对称加密只是保证了Client向Server发送的消息是安全的,因为私钥有且只有一把在Server手中,但是反过来Server向Client发送的消息就不是安全的,因为公钥是公开的大家都能下载,也就都能解密信息。
HTTPS 安全传输
超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,常称为 HTTP over TLS,HTTP over SSL 或 HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
1.加密过程:
- 服务器把自己的公开密钥登录至数字证书认证机构。
- 数字证书认证机构用自己的私有密钥向服务器的公开密码署数字签名并颁发公钥证书。
- 客户端拿到服务器的公钥证书后,使用数字签名认证机构的公开密钥,向数字证书认证机构验证公钥证书上的数字签名,以确认服务器的公开密钥的真实性。
- 客户端拿到服务器的公钥证书后,使用数字签名认证机构的公开密钥,向数字证书认证机构验证公钥证书上的数字签名,以确认服务器的公开密钥的真实性。
- 使用服务器的公开密钥对报文加密后发送。
- 服务器用私有密钥对报文解密。
2.工作流程分为 3大阶段
-
认证服务器。浏览器内置一个受信任的CA机构 列表,并保存了这些CA机构的证书。第一阶段服务器会提供经CA机构认证颁发的服务器证书,如果认证该服务器证书的CA机构,
存在于浏览器的受信任CA机构列表中,并且服务器证书中的信息与当前正在访问的网站(域名等)一致,那么浏览器就认为服务端是可信的,并从服务器证书中取得服务器公钥,用于
后续流程。否则,浏览器将提示用户,根据用户的选择,决定是否继续。当然,我们可以管理这个受信任CA机构列表,添加我们想要信任的CA机构,或者移除我们不信任的CA机构。 -
协商会话密钥。客户端在认证完服务器,获得服务器的公钥之后,利用该公钥与服务器进行加密通信,协商出两个会话密钥,分别是用于加密客户端往服务端发送数据的客户端会话密钥,用于加密服务端往客户端发送数据的服务端会话密钥。在已有服务器公钥,可以加密通讯的前提下,还要协商两个对称密钥的原因,是因为非对称加密相对复杂度更高,在数据传输过程中,使用对称加密,可以节省计算资源。另外,会话密钥是随机生成,每次协商都会有不一样的结果,所以安全性也比较高。
-
加密通讯。此时客户端服务器双方都有了本次通讯的会话密钥,之后传输的所有Http数据,都通过会话密钥加密。这样网路上的其它用户,将很难窃取和篡改客户端和服务端之间传输的数据,从而保证了数据的私密性和完整性。
Alamofire 安全传输
1. 配置自签名信息
在 ServerTrustEvaluation 类中可以看到源码
通过实现 协议 ServerTrustEvaluating
分别对应的类代表不同的类型:
- DefaultTrustEvaluator 默认策略,只有合法证书才能通过验证
- RevocationTrustEvaluator 对注销证书做的一种额外设置
- PinnedCertificatesTrustEvaluator 证书验证模式,代表客户端会将服务器返回的证书和本地保存的证书中的 所有内容 全部进行校验,如果正确,才继续执行。
- PublicKeysTrustEvaluator 公钥验证模式,代表客户端会将服务器返回的证书和本地保存的证书中的 PublicKey 部分 进行校验,如果正确,才继续执行。
- CompositeTrustEvaluator 使用提供的验证,只有所有项通过,才信任。
- DisabledEvaluator 该选项下验证一直都是通过的,无条件信任。
2. 证书的获取
/// Returns all valid `cer`, `crt`, and `der` certificates in the bundle.
var certificates: [SecCertificate] {
return paths(forResourcesOfTypes: [".cer", ".CER", ".crt", ".CRT", ".der", ".DER"]).compactMap { path in
guard let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData,
let certificate = SecCertificateCreateWithData(nil, certificateData) else { return nil }
return certificate
}
}
/// Returns all pathnames for the resources identified by the provided file extensions.
///
/// - Parameter types: The filename extensions locate.
///
/// - Returns: All pathnames for the given filename extensions.
func paths(forResourcesOfTypes types: [String]) -> [String] {
return Array(Set(types.flatMap { type.paths(forResourcesOfType: $0, inDirectory: nil) }))
}
采用的是计算型属性,遍历整个项目的 bundle 获取 “.cer”, “.CER”, “.crt”, “.CRT”, “.der”, “.DER”
然后获取文件中data 数据
3. 获取公钥key
/// Returns all public keys for the valid certificates in the bundle.
var publicKeys: [SecKey] {
return certificates.af.publicKeys
}
4. 接受质询
open func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
eventMonitor?.urlSession(session, task: task, didReceive: challenge)
let evaluation: ChallengeEvaluation
switch challenge.protectionSpace.authenticationMethod {
case NSURLAuthenticationMethodServerTrust:
evaluation = attemptServerTrustAuthentication(with: challenge)
case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM,
NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate:
evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task)
default:
evaluation = (.performDefaultHandling, nil, nil)
}
if let error = evaluation.error {
stateProvider?.request(for: task)?.didFailTask(task, earlyWithError: error)
}
completionHandler(evaluation.disposition, evaluation.credential)
}
challenge 就是为了验证用户身份,向访问者发送一个质询,然后访问者需要提供一个正确的回答以示身份