Ktor 客户端 IOS 和自签名证书

Posted

技术标签:

【中文标题】Ktor 客户端 IOS 和自签名证书【英文标题】:Ktor client IOS and self-signed certificate 【发布时间】:2020-05-17 04:48:22 【问题描述】:

我在访问内部开发服务器的 ios 应用程序中在 iOS 中使用 Ktor 和 Kotlin/native。开发服务器使用由不公开信任的内部 CA 颁发的证书。

尝试使用以下代码访问服务器时:

  internal suspend fun performHttp(url : String)
    
        // URL is a self signed HTTPS: request
        val client = HttpClient(Ios) 

        val response = client.get<String>(url)
        println(response)
    

它会抛出以下异常:

TIC SSL Trust Error [32:0x281956dc0]: 3:0
esri2[470:136341] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9807)
esri2[470:136341] Task <F3CC4C40-0231-4E58-97F3-F457D5A18BB0>.<1> HTTP load failed (error code: -1202 [3:-9807])
 esri2[470:136417] Task <F3CC4C40-0231-4E58-97F3-F457D5A18BB0>.<1> finished with error - code: -1202
esri2[470:136211] Task <F3CC4C40-0231-4E58-97F3-F457D5A18BB0>.<1> load failed with error Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “server1.internal.lan” which could put your confidential information at risk." UserInfo=NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
    "<cert(0x12b094e00) s: server1.internal.lan i: Internal-Issuing-CA2>",

如何让 Ktor 相信它应该访问这个 URL,或者忽略不受信任的证书?是的,我知道不应忽视不受信任的证书,但这是一项实验室测试。

【问题讨论】:

看看这个,可能对你有用:***.com/a/40299837/5147552 我已经尝试过了,我在帖子中没有提到。我已使用 NSIncludesSubdomains = true 和 NSExceptionAllowsInsecureHTTPLoads = true 将域添加到 NSExceptionDomains 列表。看起来 Ktor 没有使用该配置。到目前为止的解决方法是将内部根 CA 导出为 pem 文件,并将其通过电子邮件发送到我的 iPhone,安装并信任它 (medium.com/collaborne-engineering/…)。我希望 Ktor 有更好的解决方案。 嗨,你找到真正的解决方案了吗? 不,我没有。我仍然希望有更好的解决方案来解决这个问题 【参考方案1】:

Ktor iOS engine 提供了在IosClientEngineConfig.kt 的帮助下配置底层NSURLSession 的能力。

使用它,您可以通过在config 中设置handleChallenge 的块来配置(除其他外)ChallengeHandler,如下所示:

val client = HttpClient(Ios) 
    engine 
        handleChallenge(TrustSelfSignedCertificate())
    

然后你需要在 Kotlin 中实现一个类,如下所示:

internal data class TrustSelfSignedCertificate internal constructor(
    private val validateTrust: Boolean = true
) : ChallengeHandler 

    override fun invoke(
        session: NSURLSession,
        task: NSURLSessionTask,
        challenge: NSURLAuthenticationChallenge,
        completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Unit
    ) 
        val hostname = challenge.protectionSpace.host

        val serverTrust = challenge.protectionSpace.serverTrust
        var result: SecTrustResultType = 0u

        memScoped 
            val nativeResult = alloc<SecTrustResultTypeVar>()
            nativeResult.value = result
            SecTrustEvaluate(serverTrust!!, nativeResult.ptr)
        

        val serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0)
        val serverCertificateData = SecCertificateCopyData(serverCertificate)
        val data = CFDataGetBytePtr(serverCertificateData)
        val size = CFDataGetLength(serverCertificateData)

        val cert1 = NSData.dataWithBytes(data, size.toULong())
        val pathToCert = NSBundle.mainBundle.pathForResource("myOwnCert", "cer")

        val localCertificate: NSData = NSData.dataWithContentsOfFile(pathToCert!!)!!

        if (localCertificate == cert1) 
            completionHandler(
                NSURLSessionAuthChallengeUseCredential,
                NSURLCredential.create(serverTrust)
            )
         else 
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, null)
        
    


另外,不要忘记将您的证书作为文件“myOwnCert.cer”放入您的 iOS 项目(可能在顶层)。


注意

带有 iOS 引擎的 Ktor 不尊重/使用 NSApptransportSecurity。


代码基于这个answers。

借助这个blog-post。

【讨论】:

以上是关于Ktor 客户端 IOS 和自签名证书的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发HTTPS实现之信任SSL证书和自签名证书

iOS开发HTTPS实现之信任SSL证书和自签名证书

如何使用 Ionic Cordova 框架和自签名证书绕过 iOS 11 中的 SSL 检查

Web Server CA证书签名步骤和自签名测试,支持多域名

在 ktor httpClient(js) JS 引擎中忽略自签名证书的配置

Python 3.6 SSL - 使用TLSv1.0而不是TLSv1.2密码 - (2路身份验证和自签名证书)