在互联网迅速发展的年代,基本上每天都在跟网络打交道。那么,在网络的通信中怎么保证信息的安全性呢?这篇文章,咱们就来说讲,Alamofire
做为iOS
开发中一个很是优秀的网络请求相关的第三方库,它的安全策略是怎么设计和使用的。算法
在切入正题以前,先来简单的了解一下HTTPS
相关知识,方便对后面内容的理解。若是你已经了解了,能够直接跳过这一段。swift
在之前,咱们用的更多的是HTTP
,那么是什么缘由苹果公司也主推咱们使用HTTPS
这个更安全请求方式的呢?HTTP
存在的问题:api
使用 HTTPS
通讯机制能够有效地防止这些问题。HTTPS
并不是是应用层的一种新协议,只是HTTP
通讯接口部分用 SSL
和 TLS
协议代替而已。一般 HTTP
直接跟 TCP
通讯,当使用 SSL
时,则变成先和 SSL
通讯,再由 SSL
和 TCP
通讯了。简言之,HTTPS
就是身披 SSL
协议这层外壳的 HTTP
。数组
HTTP+数据加密+身份认证+数据完整性保护=HTTPS安全
HTTPS
采用混合加密机制,就是共享秘钥加密(对称加密)和公开密钥加密(非对称加密)二者并用的混合加密机制。在交换密钥环节使用公开密钥加密的方式,以后创建通信交换报文阶段则使用共享密钥加密。公开密钥加密比共享密钥加密更加安全,那为何不全用公开密钥加密?由于与共享秘钥加密相比,处理起来更复杂、处理速度慢。HTTPS
结合了两种加密方式的优劣来实现一种混合加密的流程。如图所示:服务器
HTTPS
有单向认证和双向认证,原理基本差很少,这里就讲一下单向认证的整个流程,先看一张图:网络
HTTPS
请求:客户端向服务端发送SSL
协议版本号、加密算法种类、随机数等信息。HTTPS
协议的服务器必需要有一套数字证书,能够本身制做,也能够向组织申请。区别就是本身颁发的证书须要客户端验证经过,才能够继续访问,而使用受信任的公司申请的证书能够直接经过。这套证书其实就是一对公钥和私钥。SSL
协议版本号、加密算法种类、随机数等信息TLS
来完成的,首先会验证公钥是否有效,好比颁发机构,过时时间等等,若是发现异常,则会抛出一个警告,提示证书存在问题。若是证书没有问题,那么就生成一个随机值,而后用证书对该随机值进行加密。若是使用的是自签证书须要咱们进行安全认证,若是是CA机构颁发的证书是不须要咱们写安全认证的相关代码的。 举个Alamofire
发起HTTPS
请求的栗子🌰:session
let serverTrustPlolicies: [String: ServerTrustPolicy] = [
hostUrl: .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true)
]
self.sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPlolicies))
self.sessionManager?.request(urlString).response { (defaultResponse) in
print(defaultResponse)
}
复制代码
HTTP
相比,只是在初始化SessionManager
的时候传入了一个ServerTrustPolicyManager
对象,它是证书信任策略的管理者。ServerTrustPolicyManager
对象的时候,传入了一个[String: ServerTrustPolicy]
类型的集合做为参数并保存,key
是主机地址,value
是验证模式。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)
}
复制代码
Alamofire
安全认证策略的六种模式,其中最经常使用的有这三种:.pinCertificates
证书验证模式、.pinPublicKeys
公钥验证模式和 .disableEvaluation
不验证模式。
.performDefaultEvaluation
默认策略,只有合法证书才能经过验证.performRevokedEvaluation
对注销证书作的一种额外设置.pinCertificates
证书验证模式,表明客户端会将服务器返回的证书和本地保存的证书中的 全部内容 所有进行校验,若是正确,才继续执行。.pinPublicKeys
公钥验证模式,表明客户端会将服务器返回的证书和本地保存的证书中的 PublicKey部分 进行校验,若是正确,才继续执行。.disableEvaluation
该选项下验证一直都是经过的,无条件信任。.customEvaluation
自定义验证,须要返回一个布尔类型的结果。.pinCertificates
证书验证模式。它有三个关联值:
certificates
表明的是证书validateCertificateChain
表明是否验证证书链validateHost
表明是否验证子地址Alamofire
为咱们提供了一个方法ServerTrustPolicy.certificates()
方便使用。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
}
复制代码
Bundle.main
中查找,咱们也能够指定存放证书的Bundle
来查找。URLSessionTaskDelegate
的下面这个方法。open func urlSession( _ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
guard taskDidReceiveChallengeWithCompletion == nil else {
taskDidReceiveChallengeWithCompletion?(session, task, challenge, completionHandler)
return
}
if let taskDidReceiveChallenge = taskDidReceiveChallenge {
let result = taskDidReceiveChallenge(session, task, challenge)
completionHandler(result.0, result.1)
} else if let delegate = self[task]?.delegate {
delegate.urlSession(
session,
task: task,
didReceive: challenge,
completionHandler: completionHandler
)
} else {
urlSession(session, didReceive: challenge, completionHandler: completionHandler)
}
}
复制代码
若是taskDidReceiveChallengeWithCompletion
有值的话,直接回调这个闭包,这就说明咱们能够本身实现验证的逻辑。可见Alamofire
是很是的友好的,既提供了常规实现方式,也支持开发者自定义实现。闭包
继续跟踪代码进入到delegate.urlSession
方法里面app
而后会执行红框所示的方法,获取的是前面设置的验证模式,而后执行evaluate
方法
public func evaluate(_ serverTrust: SecTrust, forHost host: String) -> Bool {
var serverTrustIsValid = false
switch self {
// 省略没法代码.....
case let .pinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
if validateCertificateChain {
let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
SecTrustSetPolicies(serverTrust, policy)
SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray)
SecTrustSetAnchorCertificatesOnly(serverTrust, true)
serverTrustIsValid = trustIsValid(serverTrust)
} else {
let serverCertificatesDataArray = certificateData(for: serverTrust)
let pinnedCertificatesDataArray = certificateData(for: pinnedCertificates)
outerLoop: for serverCertificateData in serverCertificatesDataArray {
for pinnedCertificateData in pinnedCertificatesDataArray {
if serverCertificateData == pinnedCertificateData {
serverTrustIsValid = true
break outerLoop
}
}
}
}
// 省略没法代码.....
return serverTrustIsValid
}
复制代码
if
代码块,大概步骤以下:
SecPolicyCreateSSL
:建立策略,是否验证hostSecTrustSetPolicies
:为待验证的对象设置策略trustIsValid
:进行验证,成功返回YES
.pinPublicKeys
这个枚举值,第一个参数传公钥,其余参数和证书验证模式同样。Alamofire
一样为咱们提供了获取公钥的方法ServerTrustPolicy.publicKeys()
,直接调用这个方法便可。这篇文章大概聊了一下HTTPS
的加密流程,以及经过如何Alamofire
请求HTTPS
的接口和网络挑战流程的分析。固然,若是想完全明白HTTPS
的实现方式,还需继续学习。推荐一本书《图解HTTP》,讲的很是通俗易懂,文章的几张图片也是来源于这本书。
有问题或者建议和意见,欢迎你们评论或者私信。 喜欢的朋友能够点下关注和喜欢,后续会持续更新文章。