“从传输流接收到意外的 EOF 或 0 字节”Azure WebService

dko*_*ene 8 c# client-certificates azure x509certificate2 tls1.2

我遇到以下问题:我构建了一个应作为 Azure Web 服务运行的 Web 服务,它调用外部 API 检索一些数据。对于连接,外部公司向我提供了一个证书,我已成功将其存储在 Azure Keyvault 中。经过一番尝试和错误后,我在本地测试了下面的代码块,成功验证了证书是否已从保管库中成功检索。这导致我想要检索的数据得到成功响应。到目前为止一切顺利 - 直到我将其发布到 Azure。一切似乎工作正常,但是我收到以下错误消息:

从传输流接收到意外的 EOF 或 0 字节

我已经用完谷歌的前5页了。我不断寻找有关 TLS 的答案,但在测试选项时我明确将其设置为正确的版本(即使在这个代码片段中,我实际上也只使用 TLS 1.2 就很好)。

这是什么原因造成的?我是否缺少一些神秘的 Azure 配置设置?正如我所说,该代码在我的计算机上 100% 运行。问题似乎不是钥匙或金库。最大的区别是,我在本地以租户管理员身份运行代码,但是我为应用程序服务提供了托管身份,并具有对 keyvault 的正确权限。

我还将提供堆栈跟踪。var 结果 = 等待 client.GetAsync(url);

错误抛出于

var result = await client.GetAsync(url);
Run Code Online (Sandbox Code Playgroud)

我希望我已经提供了足够的信息。先感谢您

代码片段:

 public async Task<string>GetData(string url) {
  try {
    var client = await GetHttpClient();
    var result = await client.GetAsync(url);
    if (result.IsSuccessStatusCode) {
      var content = await result.Content.ReadAsStringAsync();
      return content;
    } else {
      Exception ex = new Exception("Failed getting data: " + result.Content.ReadAsStringAsync().Result);
      throw ex;
    }
  } catch (Exception ex) {
    _telemetry.TrackException(ex);
    throw;
  }
}
public async Task<HttpClient> GetHttpClient() {
  var cert = await GetCertFromVault();
  var handler = new HttpClientHandler() {
    ClientCertificateOptions = ClientCertificateOption.Manual,
    SslProtocols = SslProtocols.Tls 
    | SslProtocols.Tls11 
    | SslProtocols.Tls12,
  };
  handler.ClientCertificates.Add(cert);
  handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
  var client = new HttpClient(handler);
  return client;
}

async Task<X509Certificate2> GetCertFromVault() {
  try {
    string keyVaultUrl = _configuration["KeyVault"];
    string certKeyName = _configuration["CertKeyName"];
    
    var cred = new DefaultAzureCredential();

    //Get certificate as secret as to include the key:
    var keyVaultClient = new SecretClient(new Uri(keyVaultUrl), cred);
    var certResponse = await keyVaultClient.GetSecretAsync(certKeyName);
    byte[] cert = System.Convert.FromBase64String(certResponse.Value.Value);

    //Convert retrieved values to X509Certificate2
    var resultKey = new X509Certificate2(cert, "", X509KeyStorageFlags.MachineKeySet
                         | X509KeyStorageFlags.PersistKeySet
                         | X509KeyStorageFlags.Exportable);
    return resultKey;

  } catch (Exception ex) {
    _telemetry.TrackException(ex);
    throw;
  }
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.IO.IOException:  Received an unexpected EOF or 0 bytes from the transport stream.
   at System.Net.Security.SslStream.<FillHandshakeBufferAsync>g__InternalFillHandshakeBufferAsync|182_0[TIOAdapter](TIOAdapter adap, ValueTask`1 task, Int32 minSize)
   at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
   at MyService.MyClient.GetData(String url) in [path]\MyClient.cs:line 40
Run Code Online (Sandbox Code Playgroud)

第 40 行对应于

var result = await client.GetAsync(url);
Run Code Online (Sandbox Code Playgroud)