我在Windows上运行以下websocket客户端代码,并且一切正常-像预期的那样。但是,如果将代码发布为linux-arm
并复制到RaspberryPi3(在Raspian下运行),它将最终以AuthenticationException
结束。
csproj文件内容:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.1" />
</ItemGroup>
连接尝试:(引发异常的点)
private readonly ClientWebSocket _socket;
public ApiConnection()
{
_socket = new ClientWebSocket();
}
public async Task Connect()
{
// the uri is like: wss://example.com/ws
await _socket.ConnectAsync(new Uri(_settings.WebSocketUrl), CancellationToken.None);
if (_socket.State == WebSocketState.Open)
Console.WriteLine("connected.");
}
异常堆栈:
System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
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.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
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.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.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.WebSocketHandle.<ConnectAsyncCore>d__24.MoveNext()
at System.Net.WebSockets.WebSocketHandle.<ConnectAsyncCore>d__24.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.ClientWebSocket.<ConnectAsyncCore>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
目标websocket服务器在Ubuntu上的nginx代理后面运行。我认为问题取决于客户端,因为如果代码在Windows上执行,则一切正常。
我也尝试将CA证书导入到Raspians的“证书存储”中。没有运气。
更新:
http连接(ws://)在Linux上也可以使用。看来,
WebSocketClient
不信任我的LetsEncrypt证书吗? 最佳答案
当浏览器/客户端不信任服务器向其抛出的SSL证书时,就会发生这种情况。
要进行测试,请在浏览器中的同一网站上加载相同的url或一个url,您应收到警告。
解决证书问题后,警告将消失。
解决SSL证书问题的确切过程取决于许多因素,例如...
操作系统,Web服务器,证书颁发机构,证书提供者门户,因此几乎没有人可以在此为您提供有关修复证书问题的详细信息,但是那...
但是在SE网络上对此有一些一般性建议...
https://unix.stackexchange.com/questions/90450/adding-a-self-signed-certificate-to-the-trusted-list
https://unix.stackexchange.com/questions/17748/trust-a-self-signed-pem-certificate
就您而言,由于rasbian基于debian,因此一些标准的debian建议可能会有所帮助...
在Debian中,证书存储位于/etc/ssl/certs/中。默认情况下,该目录包含一系列符号链接(symbolic link),这些符号链接(symbolic link)指向由ca-certificates软件包安装的证书(包括由c_rehash(1)生成的所需符号链接(symbolic link))和一个ca-certificates.crt,后者是所有这些证书的串联。由update-ca-certificates(8)命令管理的所有内容均负责更新符号链接(symbolic link)和ca-certificates.crt文件。
将新的(CA)证书添加到存储中非常容易,因为update-ca-certificates(8)也在/usr/local/share/ca-certificates/中查找文件,管理员只需将新证书放入此目录中的PEM格式(扩展名为.crt),并以root用户身份运行update-ca-certificates(8)。系统上的所有应用程序(wget,...)现在都应该信任它。
另一个可能的解决方案可能是“我相信我的代码不会请求错误的url,因此我将忽略SSL证书错误”,您可以使用类似的方法...
C# Ignore certificate errors?
...但是那不是理想的,至少它可以为您提供解决方法,直到您可以解决问题为止,最坏的情况下您仍然可以进行检查,但是可以编写自己的检查而不是仅仅返回true。
最后一点:
我经常发现无论使用什么操作系统,在重新进行一次测试或两次检查/检查之间的简单操作就可以清除某些通常不被认为是问题的东西。
关于c# - Linux上的ClientWebSocket抛出AuthenticationException(SSL),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45691565/