基于cloudflare做双向认证,上一篇已经说过,这里主要说一下ios终端如何做双向认证或单向认证终端。
ios中,如果需要做双向认证,必须得有一个终端的pkcs7或者pkcs12证书,然后还需要一个服务端的xxxx.cer证书(类似公钥)。
但是cloudflare并没有提供服务端的cer证书,只提供客户端证书。所以,只做单向的客户端认证也可以。其目的都是为了让burpsuite之类的抓包工具无法获取通讯的请求。
具体的设置之前链接中同样设置即可,然后把生成的pkcs12证书放入ios终端代码里,并拖入项目根目录。

然后在xx项目.xcodeproj文件里,找到Build Phases标签的Copy Bundle Resources项,点击添加按钮,导入刚刚的证书文件即可:

然后在ViewController.swift里面写入测试代码,查看能不能通过证书访问测试地址(前提条件是,测试地址已经开启了证书认证),代码如下:
import UIKit
import SwiftHTTP
class ViewController: UIViewController {
let selfSignedHosts = ["sslssl.xxxxxxxx.co"] //测试地址
override func viewDidLoad() {
super.viewDidLoad()
do {
let opt = try HTTP.GET("https://sslssl.xxxxxxxx.co")
opt!.auth = { challenge in
//认证服务器(这里不使用服务器证书认证,只需地址是我们定义的几个地址即可信任)
if challenge.protectionSpace.authenticationMethod
== NSURLAuthenticationMethodServerTrust
&& self.selfSignedHosts.contains(challenge.protectionSpace.host) {
print("服务器认证!")
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
return credential
}
//认证客户端证书
else if challenge.protectionSpace.authenticationMethod
== NSURLAuthenticationMethodClientCertificate
{
print("客户端证书认证!")
//获取客户端证书相关信息
let identityAndTrust:IdentityAndTrust = self.extractIdentity();
let urlCredential:URLCredential = URLCredential(
identity: identityAndTrust.identityRef,
certificates: identityAndTrust.certArray as? [AnyObject],
persistence: URLCredential.Persistence.forSession)
return urlCredential
}
// 其它情况(不接受认证)
else {
print("其它情况(不接受认证)")
return nil
}
}
HTTP.GET("https://sslssl.xxxxxxxx.co"){ response in
print("访问成功,获取数据如下:")
print(response.text as Any)
}
} catch let error {
print("请求失败: \(error)")
}
}
//获取客户端证书相关信息
func extractIdentity() -> IdentityAndTrust {
var identityAndTrust:IdentityAndTrust!
var securityError:OSStatus = errSecSuccess
let path: String = Bundle.main.path(forResource: "panda", ofType: "p12")! //证书名字
let PKCS12Data = NSData(contentsOfFile:path)!
let key : NSString = kSecImportExportPassphrase as NSString
let options : NSDictionary = [key : "123123123aaaa"] //客户端证书密码
var items : CFArray?
securityError = SecPKCS12Import(PKCS12Data, options, &items)
if securityError == errSecSuccess {
let certItems:CFArray = (items as CFArray?)!;
let certItemsArray:Array = certItems as Array
let dict:AnyObject? = certItemsArray.first;
if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {
let identityPointer:AnyObject? = certEntry["identity"]
let secIdentityRef:SecIdentity = (identityPointer as! SecIdentity?)!
print("\(String(describing: identityPointer)) :::: \(secIdentityRef)")
let trustPointer:AnyObject? = certEntry["trust"]
let trustRef:SecTrust = trustPointer as! SecTrust
print("\(String(describing: trustPointer)) :::: \(trustRef)")
let chainPointer:AnyObject? = certEntry["chain"]
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef,
trust: trustRef, certArray: chainPointer!)
}
}
return identityAndTrust;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
//定义一个结构体,存储认证相关信息
struct IdentityAndTrust {
var identityRef:SecIdentity
var trust:SecTrust
var certArray:AnyObject
}
运行结果:

调试过程中,如果需要重新安装或者修改测试地址。需要command+shift+k 清理编译缓存,且删除手机应用重新安装….
证书密码,取决于终端分段存储隐藏的够不够好。