Alamofire HTTPS自签名证书校验

根据项目需求,需要进行HTTPS网络请求并添加证书校验过程,由于没有做过,前前后后研究了两个多星期,才通过校验,可以正常进行网络请求,不多说了直接上代码

在进行自签名证书之前,需要做一些操作

  • 服务器会给你两个证书,一个是root.cer证书(根证书),一个是sub.cer(应该叫什么我也不清楚了,就称为子证书吧);你需要将这两个证书放到钥匙串中,然后在导出 ".cer" 格式的证书,然后在将这两个导出的证书通过openssl生成一个新证书:
openssl s_client -connect www.baidu.com /dev/null | openssl x509 -outform DER > https.cer

然后将这三个证书放到你的项目中,那么前期过程就已经结束了

  • 设置程序中的info.plist
    (由于我们使用的是自签名的证书,而苹果ATS(App Transport Security)只信任知名CA颁发的证书,所以在iOS9下即使是HTTPS请求还是会被ATS拦截。)
    (验证该域名是否通过ats认证 网上有很多,请自行搜索)
NSAppTransportSecurity
    
        NSAllowsArbitraryLoads
        
        NSExceptionDomains
        
            你请求的域名
            
                NSExceptionRequiresForwardSecrecy
                
                NSExceptionMinimumTLSVersion(TLS最低支持版本,需要问你的后台)
                TLSv1.2
                NSExceptionAllowsInsecureHTTPLoads
                
            
        
    
  • 开始正式验证
func setAlamofireHttps() {
        
        shareSessionManager.delegate.sessionDidReceiveChallenge = { (session: URLSession, challenge: URLAuthenticationChallenge) in
            
            let method = challenge.protectionSpace.authenticationMethod

            if method == NSURLAuthenticationMethodServerTrust {
                
                //验证服务器,直接信任或者验证证书二选一,推荐验证证书,更安全
                //服务器证书信任
                return NetworkRequest.trustServerWithCer(challenge: challenge)
                //不校验服务器证书直接信任
//                return NetworkRequest.trustServer(challenge: challenge)
                
            } else if method == NSURLAuthenticationMethodClientCertificate {
                
                //认证客户端证书
                return NetworkRequest.sendClientCer()
                
            } else {
                
                //其他情况,不通过验证
                return (.cancelAuthenticationChallenge, nil)
                
            }
            
        }
        
    }
 //不做任何验证,直接信任服务器(这个方法使用暂时没有通过,后续在进行研究)
    static private func trustServer(challenge: URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?) {
        
        let disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
        let credential = URLCredential.init(trust: challenge.protectionSpace.serverTrust!)
        return (disposition, credential)
        
    }

//验证服务器证书(重点)
    static private func trustServerWithCer(challenge: URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?) {
        
        
        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
        var credential: URLCredential?
        
        
        //获取服务器发送过来的证书
        let serverTrust:SecTrust = challenge.protectionSpace.serverTrust!
        //获取本地证书(因为自签名证书你需要进行添加锚点,该方法是Alamofire提供的,自动获取该工程下的本地证书,自动添加锚点)
        let localCertificates = ServerTrustPolicy.certificates(in: Bundle.main)
        
        //设置校验策略
        let securityPolicy = ServerTrustPolicy.pinCertificates(certificates: localCertificates, validateCertificateChain: true, validateHost: true)
        
        //进行校验证书
        if securityPolicy.evaluate(serverTrust, forHost: challenge.protectionSpace.host) {
            Print("成功")
            disposition = URLSession.AuthChallengeDisposition.useCredential
            credential = URLCredential(trust: serverTrust)
        }else {
            Print("失败")
            disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
        }

        return (disposition, credential)
        
    }

//发送客户端证书交由服务器验证(未进行校验,该项目只需要进行单项认证)
    static private func sendClientCer() -> (URLSession.AuthChallengeDisposition, URLCredential?) {
        
        let disposition = URLSession.AuthChallengeDisposition.useCredential
        var credential: URLCredential?
        
        //获取项目中P12证书文件的路径
        let path: String = Bundle.main.path(forResource: "你本地的p12证书文件名", ofType: "p12")!
        let PKCS12Data = NSData(contentsOfFile:path)!
        let key : NSString = kSecImportExportPassphrase as NSString
        let options : NSDictionary = [key : "p12证书的密码"] //客户端证书密码
        
        var items: CFArray?
        let error = SecPKCS12Import(PKCS12Data, options, &items)
        
        if error == errSecSuccess {
            
            let itemArr = items! as Array
            let item = itemArr.first!
            
            let identityPointer = item["identity"];
            let secIdentityRef = identityPointer as! SecIdentity
            
            let chainPointer = item["chain"]
            let chainRef = chainPointer as? [Any]
            
            credential = URLCredential.init(identity: secIdentityRef, certificates: chainRef, persistence: URLCredential.Persistence.forSession)
            
        }
        
        return (disposition, credential)
        
    }

直接信任证书和上传客户端证书由服务器检验方法未进行测试,如有问题,请留言,还望多多指点,
(该方法借鉴多方文档,基本能搜到的文档都查看了,就不一一列举借鉴哪些文档了,多多包涵)

你可能感兴趣的:(Alamofire HTTPS自签名证书校验)