【发布时间】:2020-03-10 09:20:29
【问题描述】:
我注意到 GraphServiceClient 在我的 .net framework 4.6.1 MVC webapp 中连接到 Microsoft 的 Graph API 的奇怪行为(对我而言)。 我使用 System.Net.WebClient 从 https://login.microsoftonline.com/common/oauth2/v2.0 获取或刷新访问令牌,效果很好。
但是,使用 GraphServiceClient 使用 Microsoft 的 Graph API,在某些情况下会失败,返回此异常:
[AuthenticationException: 远程证书无效根据 到验证程序。]
System.Net.TlsStream.EndWrite(IAsyncResult asyncResult) +300
System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) +180[WebException:底层连接已关闭:无法 为 SSL/TLS 安全通道建立信任关系。]
...(为简洁起见,我修剪了其余部分)
我尝试/检查的内容:
- 来自 graph.microsoft.com/ 的证书(Microsoft 的)在我的机器上有效且受信任,并且似乎不包含链中的其他(代理)证书。
- 使用返回 true 的 ServicePointManager.ServerCertificateValidationCallback 回调,始终有效(不再抛出异常),但我不想在我的代码中使用此 hack。
- 从上述 hack 调试 ServerCertificateValidationCallback 时,sslPolicyErrors 参数似乎总是设置为“SslPolicyErrors.none”,那么证书验证什么时候会失败?
-
- 使用 System.Net.WebClient 来使用图形 API 而不是 GraphServiceClient,始终可以正常工作。 GraphServiceClient 在证书检查方面比 System.Net.WebClient 做得更多?(编辑:我的错:webclient 的 ServicePointManager.ServerCertificateValidationCallback 返回 true) - 使用 Postman 通过相同的访问令牌使用图形 API 很简单。
-
使用 System.Net.WebClient 和之后(见下面的代码)使用 GraphServiceClient 来获取相同的数据很简单,所以我可以让 GraphServiceClient 工作,只是它之前必须有其他代码连接到使用 System.Net.WebClient 的 API(这实际上是最奇怪的部分)。(编辑:我的错:这是正常的,因为 webclient 的 ServicePointManager.ServerCertificateValidationCallback 返回 true) - 在我们的暂存环境中,GraphServiceClient 可以正常工作(没有 hack 或之前的 WebClient 代码),所以我猜这是我的开发 PC 上的某些东西和 GraphServiceClient 使用的结合。
- 我的 PC 上确实启用了 Cisco AMP(但我无法将其关闭)。我们的网络中没有代理服务器。
代码:
private static GraphServiceClient GetGraphClient(string accessToken) {
return new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) => {
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
return Task.FromResult(0);
}));
}
async public static Task<List<Appointment>> GetAppointments(string accessToken, int eventsAmountToGet) {
List<QueryOption> queryOptions = new List<QueryOption>(){
new QueryOption("startDateTime", DateTime.UtcNow.ToString("o")),
new QueryOption("endDateTime", DateTime.UtcNow.AddDays(30).ToString("o"))
};
GraphServiceClient graphClient = GetGraphClient(accessToken);
//the following line will fail (remote certificate ...)
IUserCalendarViewCollectionPage result = await graphClient.Me.CalendarView.Request(queryOptions).GetAsync();
return result.Select(x => new Appointment {
Subject = x.Subject.ToString(),
Start = x.Start.ToDateTime(),
End = x.End.ToDateTime(),
Organiser = x.Organizer.EmailAddress.Name
}).Take(eventsAmountToGet).ToList();
}
编辑: 当使用“ServicePointManager.ServerCertificateValidationCallback return true”hack 时,我在 Fiddler 中看到了这些数据。 让我担心的是请求中的“时间”字符串,这似乎是过去的。该字符串是在哪里生成的?
请求原始:
连接 graph.microsoft.com:443 HTTP/1.1 主机:graph.microsoft.com
找到了与 SSLv3 兼容的 ClientHello 握手。提琴手提取 下面的参数。
版本:3.3 (TLS/1.2) 随机:5E 67 B7 58 60 39 A6 18 3B 07 3C F0 88 17 E4 85 A7 3C 58 76 85 DE F4 0F EF 4C 76 ED DB 10 52 DE “时间”: 2/03/2017 1:29:18 会话 ID:43 4C 00 00 8C 73 51 69 9E 8B FB 24 8B E2 6B C2 B5 AA 0B E1 45 20 80 F4 98 BE A2 03 DF 1E D8 B3 扩展: server_name graph.microsoft.com supported_groups x25519 [0x1d], secp256r1 [0x17]、secp384r1 [0x18] ec_point_formats 未压缩 [0x0] 签名_algs rsa_pkcs1_sha256,rsa_pkcs1_sha384, rsa_pkcs1_sha1、ecdsa_secp256r1_sha256、ecdsa_secp384r1_sha384、 ecdsa_sha1、dsa_sha1、rsa_pkcs1_sha512、ecdsa_secp521r1_sha512 SessionTicket 为空 extended_master_secret 为空 renegotiation_info 00 密码: [C02C] TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 [C02B] TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 [C030] TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 [C02F] TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [009F] TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 [009E] TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 [C024] TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 [C023] TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 [C028] TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 [C027] TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 [C00A] TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA [C009] TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA [C014] TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA [C013] TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA [009D] TLS_RSA_WITH_AES_256_GCM_SHA384 [009C] TLS_RSA_WITH_AES_128_GCM_SHA256 [003D] TLS_RSA_WITH_AES_256_CBC_SHA256 [003C] TLS_RSA_WITH_AES_128_CBC_SHA256 [0035] TLS_RSA_WITH_AES_256_CBC_SHA [002F] TLS_RSA_WITH_AES_128_CBC_SHA [000A] SSL_RSA_WITH_3DES_EDE_SHA
压缩:[00] NO_COMPRESSION
原始响应:
HTTP/1.1 200 连接已建立 FiddlerGateway: Direct StartTime: 16:50:48.111 连接:关闭
加密的 HTTPS 流量流经此 CONNECT 隧道。 HTTPS Fiddler 中启用了解密,因此解密的会话在 此隧道将显示在 Web 会话列表中。
安全协议:Tls12 密码:Aes128 128bits 哈希算法:Sha256 ?bits 密钥交换:ECDHE_RSA (0xae06) 255bits
== 服务器证书 ========== [主题] CN=graph.microsoft.com
[发行人] CN=Microsoft IT TLS CA 2,OU=Microsoft IT,O=Microsoft 公司,L=雷德蒙德,S=华盛顿,C=美国
[序列号] 20000549F729A8A47312D9F3220000000549F7
[不早于] 27/01/2019 20:09:45
[不在之后] 27/01/2021 20:09:45
[指纹] 2D4A597DE7EA5A28474EEAB141E8A085907A900A
[SubjectAltNames] graph.microsoft.com
【问题讨论】:
-
最好的调试方法是使用像wireshark或fiddler这样的嗅探器。比较第一个良好请求中的标头和第一个错误请求中的标头。请求和响应是http。使用 TCP 执行 TLS/SSL 验证。因此,您应该会同时看到 TCP 和 HTTP 消息。 TCP 可能失败并显示 [FIN] 指示连接已关闭。一个好的响应应该包含 200 OK 的状态。不良状态通常在 400 或 500 之间。请注意,使用令牌/cookie 会绕过验证。我有时会在两次尝试之间删除 cookie,以免感到困惑。
-
当我使用 fiddler 时,什么都没有了。邮递员返回:
Could not get any response There was an error connecting to https://graph.microsoft.com/v1.0/me/calendarview?startDateTime=2020-03-06T13:21:26.5905396Z&endDateTime=2020-03-30T13:21:26.5905396Z.Graphclient(使用代理到 localhost:8888)仍然返回相同的异常。 Fiddler 仅显示带有 TLS 信息的“隧道”条目,但没有实际数据条目 -
您是否设置了 fiddler 以返回 TCP 和 HTTP 消息?看起来代码想要在端口 8888 上的本地主机上使用代理。尝试从 cmd.exe >Netstat -a 并查看服务器是否在端口 8888 上运行。修复您的输出消息,这样它就不会说您正在尝试连接到 graph.microsoft .com。您实际上是在尝试连接到 localhost 端口 8888。
-
不知道如何配置Fiddler返回TCP消息。提琴手网络服务肯定正在运行,我在 netstat -a 上获得了很多条目,并且可以浏览到 localhost:8888。不确定“修复输出消息”是什么意思。 (顺便说一句:感谢您的帮助)
-
它在过滤器中的协议下。不要在我正在使用的机器上运行 Fiddler。我找不到显示如何编辑过滤器的好网页。
标签: c# .net ssl-certificate microsoft-graph-api webclient