为什么 C# Google.Cloud.Firestore 库无法连接到企业 MITM 防火墙?
Why does a C# Google.Cloud.Firestore library fail to connect with an enterprise MITM firewall?
图书馆的具体错误信息
CompletedListGrpc.Core.RpcException: Status(StatusCode=Unavailable,
Detail="Connect Failed")
- 我特别提到这个库:https://github.com/googleapis/google-cloud-dotnet/tree/master/apis/Google.Cloud.Firestore
- 我特别遇到 google-cloud-firestore 服务的问题(尽管该问题可能发生在另一个依赖库中,也许是身份验证)
- 有问题的防火墙是帕洛阿尔托网络。它具有安装在企业工作站上且受信任的企业证书。防火墙本质上充当 MITM 来解密流量,以便更深入地分析 TLS 流量。
当为 firestore.googleapis.com 禁用防火墙 MITM 功能时,库工作正常。启用中间人攻击功能后,它不起作用。
子题:
1) 库代码是否有硬编码证书检查? (我找不到)
public static gaxgrpc::ServiceEndpoint DefaultEndpoint { get; } = new gaxgrpc::ServiceEndpoint("firestore.googleapis.com", 443);
- 对证书进行硬编码没有意义,因为证书会更新,有时旧证书会被撤销。
- grpc 是非常标准的并且被 Google 共享(参见 https://grpc.io/)。
- 假设 grpc 不包含下游依赖项的显式证书是合理的
- 如果 firestore 打算断言证书,可以合理地假设这行代码将与 URL
一起完成
2a) .Net Framework 是否自动信任 windows 信任库中的证书?是否需要任何代码才能完成这项工作?
.Net Framework 似乎可以与 Windows 证书存储一起使用 - 请参阅 https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working-with-certificates
2b) 也许证书只受信任但交互用户而不是整个机器,因此服务帐户看不到该证书 - 我会检查一下...
3) 如果这是导致 "Connect Failed" 的原因,图书馆是否会有关于证书的特定错误?
这可能是 GRPC 和 Windows 证书存储之间的问题。无论这是 GRPC(而不是 .Net)的根本问题还是由于 运行 它在不同的帐户下,将防火墙的正确根 CA 硬编码到应用程序中肯定会给您完全控制权。
您可以覆盖 DefaultEndpoint/Channel 以使用您自己的 ServicePoint,该服务点还包含硬编码证书
参见
var cacert = File.ReadAllText(@"../ca.crt");
var clientcert = File.ReadAllText(@"../client.crt");
var clientkey = File.ReadAllText(@"../client.key");
var ssl = new SslCredentials(cacert, new KeyCertificatePair(clientcert, clientkey));
var channel = new Channel("firestore.googleapis.com", 443, ssl);
//etc..
创建您自己的端点,然后显式提供它以覆盖 DefaultEndpoint。这是您将通过频道调用的函数。 (参见 https://github.com/googleapis/google-cloud-dotnet/blob/master/apis/Google.Cloud.Firestore.V1/Google.Cloud.Firestore.V1/FirestoreClient.cs#L550)
public static FirestoreClient Create(grpccore::Channel channel, FirestoreSettings settings = null)
{
gax::GaxPreconditions.CheckNotNull(channel, nameof(channel));
return Create(new grpccore::DefaultCallInvoker(channel), settings);
}
此外,请仔细查看 SslCredentialsTest 代码 - https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
注意:通常会使用 s_channelPool 创建频道。如果您手动创建它,它可能不会使用池 - 可能没有办法做到这一点。这对您来说可能是问题,也可能不是问题。
您可以扩展它以在运行时按名称手动从 Windows 证书存储中读取 public 证书信息,选择最新的。这意味着您可以使用 app.config 分配从 Windows 证书存储中获取的证书的 CN,这样您就无需手动发送软件的更新版本。
这 link 似乎表明默认情况下 "Publically Trusted Roots" 是可信的:https://forum.predix.io/questions/30875/event-hub-c-client-how-to-deal-with-the-tls-certif.html
var channel = new Channel("greeter.googleapis.com", new SslCredentials()); // Use publicly trusted roots.
这意味着虽然 firestore 没有 "hardcoded" 特定证书,但它通常不会与 Windows 证书存储集成,因此任何自定义安装的根 CA 都不可信。
仔细查看库源代码[https://github.com/googleapis/gax-dotnet/blob/master/Google.Api.Gax.Grpc/ChannelPool.cs]:
public Channel GetChannel(ServiceEndpoint endpoint, IEnumerable<ChannelOption> channelOptions)
{
GaxPreconditions.CheckNotNull(endpoint, nameof(endpoint));
var credentials = _lazyScopedDefaultChannelCredentials.Value.ResultWithUnwrappedExceptions();
return GetChannel(endpoint, channelOptions, credentials);
}
credentials 参数是自动填充的,在 _lazyScopedDefaultChannelCredentials
、GoogleCredential.GetApplicationDefaultAsync()
之后,我们最终到达 CreateDefaultCredentialAsync
,它指的是您可能下载的 Google 服务文件来自 firebase 某处。
注:
这个答案很可能只会导致自定义客户端凭据,而不是为自定义服务器端根 CA 提供硬编码凭据的能力。
这可能只是 Windows 证书存储配置错误。也许您 运行 软件所在的帐户无权访问正确的根 CA。不管是什么原因,有一种常见的 .Net 方法可以手动批准证书。
1) 首先,尝试简单地绕过检查的测试。参见
ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
不要让这段代码留在生产环境中,只用它看看这条路是否可行。
2) 接下来自定义此功能以手动检查根 CA 的特定证书和相关证书。强烈建议使用一个库来帮助你,但你可以让它与核心 .net 库一起工作。
见
结论
如果这个答案无效,我会删除它。
图书馆的具体错误信息
CompletedListGrpc.Core.RpcException: Status(StatusCode=Unavailable, Detail="Connect Failed")
- 我特别提到这个库:https://github.com/googleapis/google-cloud-dotnet/tree/master/apis/Google.Cloud.Firestore
- 我特别遇到 google-cloud-firestore 服务的问题(尽管该问题可能发生在另一个依赖库中,也许是身份验证)
- 有问题的防火墙是帕洛阿尔托网络。它具有安装在企业工作站上且受信任的企业证书。防火墙本质上充当 MITM 来解密流量,以便更深入地分析 TLS 流量。
当为 firestore.googleapis.com 禁用防火墙 MITM 功能时,库工作正常。启用中间人攻击功能后,它不起作用。
子题:
1) 库代码是否有硬编码证书检查? (我找不到)
public static gaxgrpc::ServiceEndpoint DefaultEndpoint { get; } = new gaxgrpc::ServiceEndpoint("firestore.googleapis.com", 443);
- 对证书进行硬编码没有意义,因为证书会更新,有时旧证书会被撤销。
- grpc 是非常标准的并且被 Google 共享(参见 https://grpc.io/)。
- 假设 grpc 不包含下游依赖项的显式证书是合理的
- 如果 firestore 打算断言证书,可以合理地假设这行代码将与 URL 一起完成
2a) .Net Framework 是否自动信任 windows 信任库中的证书?是否需要任何代码才能完成这项工作?
.Net Framework 似乎可以与 Windows 证书存储一起使用 - 请参阅 https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working-with-certificates
2b) 也许证书只受信任但交互用户而不是整个机器,因此服务帐户看不到该证书 - 我会检查一下...
3) 如果这是导致 "Connect Failed" 的原因,图书馆是否会有关于证书的特定错误?
这可能是 GRPC 和 Windows 证书存储之间的问题。无论这是 GRPC(而不是 .Net)的根本问题还是由于 运行 它在不同的帐户下,将防火墙的正确根 CA 硬编码到应用程序中肯定会给您完全控制权。
您可以覆盖 DefaultEndpoint/Channel 以使用您自己的 ServicePoint,该服务点还包含硬编码证书
参见
var cacert = File.ReadAllText(@"../ca.crt");
var clientcert = File.ReadAllText(@"../client.crt");
var clientkey = File.ReadAllText(@"../client.key");
var ssl = new SslCredentials(cacert, new KeyCertificatePair(clientcert, clientkey));
var channel = new Channel("firestore.googleapis.com", 443, ssl);
//etc..
创建您自己的端点,然后显式提供它以覆盖 DefaultEndpoint。这是您将通过频道调用的函数。 (参见 https://github.com/googleapis/google-cloud-dotnet/blob/master/apis/Google.Cloud.Firestore.V1/Google.Cloud.Firestore.V1/FirestoreClient.cs#L550)
public static FirestoreClient Create(grpccore::Channel channel, FirestoreSettings settings = null)
{
gax::GaxPreconditions.CheckNotNull(channel, nameof(channel));
return Create(new grpccore::DefaultCallInvoker(channel), settings);
}
此外,请仔细查看 SslCredentialsTest 代码 - https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
注意:通常会使用 s_channelPool 创建频道。如果您手动创建它,它可能不会使用池 - 可能没有办法做到这一点。这对您来说可能是问题,也可能不是问题。
您可以扩展它以在运行时按名称手动从 Windows 证书存储中读取 public 证书信息,选择最新的。这意味着您可以使用 app.config 分配从 Windows 证书存储中获取的证书的 CN,这样您就无需手动发送软件的更新版本。
这 link 似乎表明默认情况下 "Publically Trusted Roots" 是可信的:https://forum.predix.io/questions/30875/event-hub-c-client-how-to-deal-with-the-tls-certif.html
var channel = new Channel("greeter.googleapis.com", new SslCredentials()); // Use publicly trusted roots.
这意味着虽然 firestore 没有 "hardcoded" 特定证书,但它通常不会与 Windows 证书存储集成,因此任何自定义安装的根 CA 都不可信。
仔细查看库源代码[https://github.com/googleapis/gax-dotnet/blob/master/Google.Api.Gax.Grpc/ChannelPool.cs]:
public Channel GetChannel(ServiceEndpoint endpoint, IEnumerable<ChannelOption> channelOptions)
{
GaxPreconditions.CheckNotNull(endpoint, nameof(endpoint));
var credentials = _lazyScopedDefaultChannelCredentials.Value.ResultWithUnwrappedExceptions();
return GetChannel(endpoint, channelOptions, credentials);
}
credentials 参数是自动填充的,在 _lazyScopedDefaultChannelCredentials
、GoogleCredential.GetApplicationDefaultAsync()
之后,我们最终到达 CreateDefaultCredentialAsync
,它指的是您可能下载的 Google 服务文件来自 firebase 某处。
注:
这个答案很可能只会导致自定义客户端凭据,而不是为自定义服务器端根 CA 提供硬编码凭据的能力。
这可能只是 Windows 证书存储配置错误。也许您 运行 软件所在的帐户无权访问正确的根 CA。不管是什么原因,有一种常见的 .Net 方法可以手动批准证书。
1) 首先,尝试简单地绕过检查的测试。参见
ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
不要让这段代码留在生产环境中,只用它看看这条路是否可行。
2) 接下来自定义此功能以手动检查根 CA 的特定证书和相关证书。强烈建议使用一个库来帮助你,但你可以让它与核心 .net 库一起工作。
见
结论
如果这个答案无效,我会删除它。