iOS13 macOS 10.15下 本地测试https双向或者单项认证

2,173 阅读5分钟

最近在研究关于https安全认证的问题,但是资料感觉多(没用的复制的也不少),就写下这篇文章记录一下

注意:iOS 13和macOS 10.15中受信任证书的要求已经发生变化 具体见苹果官网

大致谷歌翻译: 所有TLS服务器证书都必须符合iOS 13和macOS 10.15中的这些新安全要求: TLS服务器证书和使用RSA密钥的颁发CA必须使用大于或等于2048位的密钥大小。使用RSA密钥大小小于2048位的证书不再受TLS信任。 TLS服务器证书和颁发CA的签名算法必须使用SHA-2系列的哈希算法。不再信任SHA-1签名证书。 TLS服务器证书必须在证书的“使用者备用名称”扩展名中显示服务器的DNS名称。证书的CommonName中的DNS名称不再受信任。 此外,2019年7月1日之后颁发的所有TLS服务器证书(如证书的NotBefore字段中所示)必须遵循以下准则: TLS服务器证书必须包含包含id-kp-serverAuth OID的ExtendedKeyUsage(EKU)扩展。 TLS服务器证书的有效期必须为825天或更短(如证书的NotBefore和NotAfter字段中所示)。 违反这些新要求的TLS服务器连接将失败,并可能导致网络故障,应用程序失败以及网站无法加载到iOS 13和macOS 10.15的Safari中。 ###通过keytool生成服务器端以及客户端证书是一种不错的选择,方便我们进行本地测试,这里我参考的资料使用keytool生成证书,但是注意!里面的一些命令和mac不大一致,另外生成的算法位数也不大对

下面是我的Mac生成证书步骤

1生成服务器证书

keytool -genkey -v -alias tomcat -keyalg RSA -keystore /Users/liguicheng/Desktop/key/tomcat.keystore  -keysize 2048 -validity 36500

参数说明:“/Users/liguicheng/Desktop/key”含义是将证书文件的保存路径,证书文件名称是tomcat.keystore; “-validity 36500”含义是证书有效期,36500表示100年,默认值是90天;“tomcat”为自定义证书名称;-keysize 2048加密算法位数

2生成客户端证书

假设客户端证书密码“123456”,其他随便填
keytool -genkey -v -alias mykey -keyalg RSA -storetype PKCS12 -keystore /Users/liguicheng/Desktop/key/mykey.p12

3让服务器信任客户端证书

服务器要信任客户端证书,必须把客户端证书添加为服务器的信任认证。
1)由于不能直接将PKCS12格式的证书库导入,必须先把客户端证书导出为一个单独的CER文件,使用如下命令:
     (下面要用到客户端证书密码“123456”)

keytool -export -alias mykey -keystore /Users/liguicheng/Desktop/key/mykey.p12  -storetype PKCS12 -storepass 123456 -rfc -file /Users/liguicheng/Desktop/key/mykey.cer

2)将该文件导入到服务器的证书库,添加为一个信任证书使用命令如下

keytool -import -v -file /Users/liguicheng/Desktop/key/mykey.cer -keystore /Users/liguicheng/Desktop/key/tomcat.keystore

3)通过 list 命令查看服务器的证书库,可以看到两个证书,一个是服务器证书,一个是受信任的客户端证书:

keytool -list -keystore /Users/liguicheng/Desktop/key/tomcat.keystore

4)让客户端信任服务器证书

keytool -keystore /Users/liguicheng/Desktop/key/tomcat.keystore  -export -alias tomcat -file /Users/liguicheng/Desktop/key/tomcat.ce

显示的信息 和我们的文件夹下

截屏2020-03-03下午6.22.48.png
截屏2020-03-03下午6.25.03.png

接下来修改tomcat配置:(你的tomcat对应的server.xml)

截屏2020-03-03下午6.26.23.png

之前的8080重定向为443
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="443" />

找到注释的8443,去掉注释,修改了443 并添加如下,keystoreFile为你的路径哈 密码是你设置的密码
    <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
    SSLEnabled="true" maxThreads="150" scheme="https"
    secure="true" clientAuth="false" sslProtocol="TLS"
    keystoreFile="/Users/liguicheng/Desktop/key/tomcat.keystore" keystorePass="123456"
    truststoreFile="/Users/liguicheng/Desktop/key/tomcat.keystore" truststorePass="123456" sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2" />

最后启动tomcat 浏览器中访问https://localhost:443,在Safari中进去之后显示不安全的我们选择证书,最后的成功后前面是带这小锁🔒的;信任证书浏览器正常访问之后,浏览器和Xcode demo代码如下:

41583281353_.pic_hd.jpg

Alamofier 5.0


这里面应该最后的struct不用写,因为最新的Alamofire5.x,已经实现了从Bundle.main中去找这个.cer文件
import UIKit
import Alamofire
class ViewController: UIViewController {


//    let evaluators = ["localhost": PinnedCertificatesTrustEvaluator(certificates: [Certificates.stackExchange], acceptSelfSignedCertificates: true, performDefaultValidation: false, validateHost: false)]
        let evaluators = ["localhost": PinnedCertificatesTrustEvaluator(certificates: [Certificates.stackExchange], acceptSelfSignedCertificates: true, performDefaultValidation: false, validateHost: false)]
    var session: Session!

    override func viewDidLoad() {
        super.viewDidLoad()

        session = Session(serverTrustManager: ServerTrustManager(evaluators: evaluators))
        session.request("https://localhost:443/")
            .response { (response) in
                print(response)
        }
    }

}


struct Certificates {
  static let stackExchange =
    Certificates.certificate(filename: "tomcat")

  private static func certificate(filename: String) -> SecCertificate {
    let filePath = Bundle.main.path(forResource: filename, ofType: "cer")!
    let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
    let certificate = SecCertificateCreateWithData(nil, data as CFData)!
    print(certificate)
    return certificate
  }
}

打印提示:

<cert(0x7ffc1bc04eb0) s: localhost i: localhost>
success(Optional(11394 bytes))

另外一种思路来验证关于https认证问题,那就是去腾讯云或者Ali云付费买一个域名,仅仅是为了测试,不需要买.com或者.cn的那种,有.xyz的那种,1元/年,申请成功后的域名,在Ali云上解析成功后,会自动给你生成tomcat,Apache,Nginx和IIS的证书,然后同样的方式配置tomcat后,在腾讯云/Ali云添加的你的域名指向你本地的ip,然后就可以测试https认证了

####腾讯云的大致界面

51583282239_.pic_hd.jpg

tomcat配置如下

keystoreFile是下载后的文件路径
keystorePass是密码
<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
               keystoreFile="/Users/liguicheng/Desktop/Tomcat/trump.xyz.jks"
               keystorePass="xxxxxxx"
               sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"
               ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA"
/>