【问题标题】:Using LXD REST API, ClientWebSocket throws 'AuthenticationException' on .Net Core, but on .Net Framework, it works well使用 LXD REST API,ClientWebSocket 在 .Net Core 上抛出“AuthenticationException”,但在 .Net Framework 上,它运行良好
【发布时间】:2019-02-09 08:30:58
【问题描述】:

我正在将 LXD.NET 移植到 .Net Standard 2.0。通过 HTTPS 实现的 REST API 可以很好地与 .Net Core 和 .Net Framework 配合使用。
但是使用 WebSocket API(例如 1.0/containers/<name>/exec ),ClientWebSocket 仅在 .Net Core 上引发身份验证异常。 (在 .Net Framework 上,它不会抛出并且运行良好。

LXD 在 Ubuntu 18.04 上运行。我在两个客户端上进行了测试,一个在 Windows 10 上运行,另一个在 Linux 上运行(运行 LXD 的同一台 linux 计算机)。

所有源代码都是Herehttps://github.com/GnicoJP/lxd-dotnet-websocket-test)。

重现步骤(服务器端)

LXD 设置

$ sudo apt install lxc lxd  
$ sudo lxd init  

我将 LXD 配置为可通过网络使用。

$ sudo lxc launch images:alpine/3.8 &lt;container_name&gt;  

我发布了一张图片。

SSL 密钥/证书生成

$ openssl genrsa 2048 > client.key  
$ openssl req -new -key client.key > client.csr  
$ openssl x509 -days 3650 -req -signkey client.key < client.csr > client.crt  
$ openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12

将 client.p12 带到客户端 PC。

我注册了 SSL 证书

$ sudo lxc config trust add client.key

源代码

入口点是Here。我正在调用 exec API。(wait-for-websocket 是真的)
解析 Exec API 的结果是 Here。我觉得 WebSocket 的 URI 没有错。
打开 ClientWebSocket 是Here。在 .Net Framework 上,WebSocket 在有/没有证书的情况下都能很好地工作。

抛出的异常

System.AggregateException
HResult=0x80131500
Message=One or more errors occurred. (Unable to connect to the remote server)
Source=System.Private.CoreLib
Stack Trace:
    at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) in Task.cs:line 2840
    at System.Threading.Tasks.Task.Wait() in Task.cs:line 2706
    at lxd_dotnet_websocket_test.Program.Main(String[] args) in lxd-dotnet-websocket-test\Program.cs:line 20

Inner Exception 1:
System.Net.WebSockets.WebSocketException: Unable to connect to the remote server
HResult=-2147467259
Stack Trace:
    at System.Net.WebSockets.WebSocketHandle.ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
    at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, CancellationToken cancellationToken)
    at LXD.ClientWebSocketExtensions.CreateAndConnectAsync(String url, API API) in .\libs\LXD\Util\ClientWebSocketExtensions.cs:line 19
    at LXD.Domain.Container.ContainerExecResult.ContainerExecResultWithWebSockets.TestCreate(API API, ContainerExec exec, JToken response, String operationUrl) in .\libs\LXD\Domain\Container.cs:line 228

Inner Exception 2:
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
HResult=-2146233087
Stack Trace:
    at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
    at System.Threading.Tasks.ValueTask`1.get_Result()
    at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    at System.Threading.Tasks.ValueTask`1.get_Result()
    at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
    at System.Threading.Tasks.ValueTask`1.get_Result()
    at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
    at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    at System.Net.WebSockets.WebSocketHandle.ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)

Inner Exception 3:
AuthenticationException: The remote certificate is invalid according to the validation procedure.
HResult=-2146233087
Stack Trace:
    at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
    at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
    at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
    at System.Net.Security.SslState.ThrowIfExceptional()
    at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
    at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
    at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
    at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__47_1(IAsyncResult iar)
    at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
    at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)

我是 StackOverflow 的初学者。如果我的问题或我的英语不好,请告诉我。

【问题讨论】:

  • 您是否总是使用与服务器相同的机器(和相同的帐户)运行?从错误消息中显示“远程证书无效”。您是否以管理员权限运行该服务?我通常建议使用像 wireshark 或 fiddler 这样的嗅探器,并比较工作应用程序和非工作应用程序中的 HTTP 标头。 HTTP 使用 TCP 作为传输层。 TCP 数据报的最大大小约为 1500 字节。所以一个 HTTP 由一个或多个 TCP 消息组成。如果 TLS 失败,它将显示在 TCP 数据报上。在 TCP [FIN] 中表示连接关闭。
  • 感谢您的回复。我没有在同一台机器上运行。但是,如果我用 .Net Framework 编译它,它运行良好(即使我从不同的机器访问。)。我想知道为什么使用 .Net Core 访问 WebSocket API 会失败。我会尝试使用 Wireshark,谢谢。
  • LXD 以管理员权限运行。我不认为它是由权限错误引起的,因为使用其他库(pylxd 等)创建的其他程序将无法访问与使用 .NetCore 构建的 websocket 相同的 websocket。
  • 我不认为问题出在代码上。我相信问题是服务器。坏服务器上的 Net Core 版本可能不同。在很多情况下,Net 库都是调用 windows dll 的包装器。因此,如果 Windows 库不同或 Net 库不同(在不同的机器上),代码并不总是有效。这就是为什么我建议发布应用程序并安装在更新 Windows dll 的部署机器上。在这种情况下,错误消息表明证书有问题。证书日期可能已过期。
  • 使用 .Net Core 和 .Net Framework 构建的程序在同一台计算机、相同的 Windows 环境、相同的证书上运行。 (如果之前的评论,“我没有在同一台机器上运行。”让你感到困惑,对不起。这意味着服务器和客户端是不同的机器。)如果证书无效,我想知道 .Net Framework 不会抛出例外。很抱歉不知道,谢谢您的回复。

标签: c# .net websocket lxd


【解决方案1】:

.Net Framework 不检查 WebSocket 中使用的证书是否可信, 但是.Net Core 可以。我无法从异常中得到解决方法,所以我调查了by using PerfView

如何解决

我安装了 LXD 的服务器证书。 将 server.crt 文件 (/var/lxd/server.crt) 带到客户端 PC,然后作为受信任的根证书安装。
请阅读如何安装:WindowsLinux

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    • 2019-02-16
    • 2022-01-20
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多