首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

WebKit Authentication Challenge 核心流程

  • 24-12-12 11:47
  • 2395
  • 9815
juejin.cn

我们知道代码发起 URLSession 请求时,会有个-URLSession:didReceiveChallenge:completionHandler:代理函数自定义认证逻辑;在使用 WebKit 时,也有个-webView:didReceiveAuthenticationChallenge:completionHandler:代理函数实现同样功能。

不难推测,WebKit 底层是使用 URLSession 时把认证函数转接到外部供开发者使用的。不过在实际的开发过程中却发现了不回调的情况,不得不挖一下内部逻辑。

Network 进程的漏斗

WebKit 是在 NetworkSessionCocoa 里面做网络请求回执处理的,跟着 Authentication Challenge 代理回调逻辑发现:

ini
代码解读
复制代码
// step1 // Proxy authentication is handled by CFNetwork internally. We can get here if the user cancels // CFNetwork authentication dialog, and we shouldn't ask the client to display another one in that case. if (challenge.protectionSpace.isProxy && sessionCocoa->proxyConfigs().isEmpty() && !sessionCocoa->preventsSystemHTTPProxyAuthentication()) return completionHandler(NSURLSessionAuthChallengeUseCredential, nil); // step2 NegotiatedLegacyTLS negotiatedLegacyTLS = NegotiatedLegacyTLS::No; if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSURLSessionTaskTransactionMetrics *metrics = task._incompleteTaskMetrics.transactionMetrics.lastObject; auto tlsVersion = (tls_protocol_version_t)metrics.negotiatedTLSProtocolVersion.unsignedShortValue; if (tlsVersion == tls_protocol_version_TLSv10 || tlsVersion == tls_protocol_version_TLSv11) negotiatedLegacyTLS = NegotiatedLegacyTLS::Yes; if (negotiatedLegacyTLS == NegotiatedLegacyTLS::No && [task respondsToSelector:@selector(_TLSNegotiatedProtocolVersion)]) { SSLProtocol tlsVersion = [task _TLSNegotiatedProtocolVersion]; if (tlsVersion == kTLSProtocol11 || tlsVersion == kTLSProtocol1) negotiatedLegacyTLS = NegotiatedLegacyTLS::Yes; } // step3 if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes && task._preconnect) return completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); …

分析相关上下文解读核心含义如下。

step1

若是代理认证且用户主动拒绝了认证弹窗,则默认处理,意味着不会回调到 WebKit 外部代理供开发者拦截。

step2

首先从 URLSession 里面的 metrics 性能数据里面读取 TLS 的版本,然后从 NSURLSessionTask 里面去 TLS 版本。 最终,若 TLS 版本是 1.0 和 1.1 则认为是 legacy TLS,估计是由于历史遗留问题不得不做特殊处理。

这里用到了几个枚举类型,tls_protocol_version_t 的值其实和 swift 里面的 tls_protocol_version_t 枚举值是一样的,kTLSProtocol1 的值也就是 Secure 系统库里面的枚举。

step3

若是 legacy TLS 且支持了 preconnect 则默认处理。preconnect 就是在网络进程还没有去加载网页的资源时,提前去与 host 对应的服务进行预连接,这个能力可能是开启的。

所以有漏斗1:若 TLS 版本低了可能永远无法走到自定义认证函数。

后续还会存在一些是否合并 challenge 的判定,如果是 serverTrust 则会正常流转。

php
代码解读
复制代码
static bool canCoalesceChallenge(const WebCore::AuthenticationChallenge& challenge) { // Do not coalesce server trust evaluation requests because ProtectionSpace comparison does not evaluate server trust (e.g. certificate). return challenge.protectionSpace().authenticationScheme() != ProtectionSpace::AuthenticationScheme::ServerTrustEvaluationRequested; }

所以有漏斗2:若 TLS 认证被网络库错误的判定为非 serverTrust。

网络库判定 serverTrust 逻辑

把 Swift 的 URLSession 源码搞下来看了下,发现竟然不支持 NSURLAuthenticationMethodServerTrust 类型,跟 OC 的实现估计是大不相同,所以这部分还不太好查。当然这也符合预期,就像 Swift URLCache 的实现也非常拙劣,跟 OC 完全不一样。

UI 进程的漏斗

目标逻辑:

scss
代码解读
复制代码
void WebPageProxy::didReceiveAuthenticationChallengeProxy(…) { if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) { m_navigationClient->shouldAllowLegacyTLS(…) { if (shouldAllowLegacyTLS) m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get()); else authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::Cancel); }); return; } m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get()); }

如果是 Legacy TLS 会走 shouldAllowLegacyTLS 函数逻辑:

  • 优先判定-webView:authenticationChallenge:shouldAllowDeprecatedTLS:;
  • 其次判定 -_webView:authenticationChallenge:shouldAllowLegacyTLS:;
  • 兜底websiteDataStore().configuration().legacyTLSEnabled() (默认 true);

而默认情况下,前两步都不会走到,所以这部分理论上不会有漏斗。而且这也是在网络进程判定是 Legacy TLS 且不支持 preconnect 才会走到。

注:本文转载自juejin.cn的波儿菜的文章"https://juejin.cn/post/7446693684223393826"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

141
iOS
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top