ios - Ktor 客户端 IOS 和自签名证书
问题描述
我在访问内部开发服务器的 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,或者忽略不受信任的证书?是的,我知道不应忽视不受信任的证书,但这是一项实验室测试。
解决方案
Ktor iOS 引擎提供了在 IosClientEngineConfig.kt的帮助下配置底层NSURLSession的能力。
有了它,您可以通过在配置中ChallengeHandler
设置块来配置(除其他外)a ,如下所示:handleChallenge
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。
该代码基于此答案。
在这篇博文的帮助下。
推荐阅读
- javascript - 在 vuex getter 中访问 Nuxt 插件功能
- r - 重新采样数据帧的时间序列并使用 R 中变量的先前值
- c++ - 如何查看驻留在进程中的 DLL 的内存视图?
- swift - 在 Flutter 的 Firebase 消息传递的 iOS 端处理后台推送通知
- node.js - 将 Google 表格连接到 Node JS 时出错
- java - java StringIndexOutOfBoundsException: -1
- sql-server - 如何从 SQL Server 数据库中保存存档
- r - 搜索和使用数据库
- html - Bootstrap - 防止 div 由于更大的文本而扩展
- html - `\n` 不在内部创建新行
标签