【问题标题】:SslStream on Mono not fully closingMono 上的 SslStream 未完全关闭
【发布时间】:2017-02-02 12:51:07
【问题描述】:

我目前正在使用我们设计用于与 Xamarin 移动应用程序通信的服务器应用程序。我们正在使用一个旧的消息传递库,它与TcpClient 建立连接并保持连接打开(每 3 秒发送一次心跳消息)。我们通过用SslStream 包装TcpClient 流将SSL 添加到库中。我们已经在 Windows 上运行了服务器应用程序,它运行良好,但我们的最终目标是 BeagleBoneBlack 上的 Mono

但是,当我们在移动应用端关闭流和客户端,然后尝试重新启动新连接时,SslStream.AuthenticateAsServer(...) 将不会在服务器上完成。但是,如果我完全关闭移动应用程序,服务器会抛出异常。此时,我重新打开应用程序,并且可以毫无问题地重新连接。

因此,似乎在应用程序或服务器端都没有关闭低级别的东西。奇怪的是,当服务器在 Windows 上运行时,我在两者上运行完全相同的代码并且我没有遇到问题。

这是我关闭/处理流的代码

public async Task Disconnect()
{
    if (!UseAsync)
    {
        semaphore.Wait();
    }
    try
    {
        if (UseSSL)
        {
            SslStream?.Close();
        }
        Client?.GetStream()?.Close();
        Client?.Close();
    }
    catch (Exception ex) // Assuming we had an exception from trying to close the sslstream
    {
        logger.Error(ex, "Did not close/dispose correctly: {0}", ex.ToString());
    }
    finally
    {
        SslStream = null;
        Client = null;
        if (!UseAsync)
        {
            semaphore.Release();
        }
    }
}

编辑:这应该不重要,因为问题似乎出在服务器的某个地方,并且客户端和服务器的 ssl 代码几乎相同,但如果有人问,这里是客户端断开代码

public async Task Disconnect()
{
    try
    {
        if (UseSSL)
        {
            _sslStream?.Close();
        }
        Client?.GetStream()?.Close();
        Client?.Close();
    }
    catch // Assuming we had an exception from trying to close the sslstream
    {
        // Ignore exceptions since we've already closed them
    }
    finally
    {
        _sslStream = null;
        Client = null;
    }
}

编辑 2

还应注意,我发现至少有一个bug report 看起来与我正在处理的问题相同。从这个错误报告中看,它并没有得到解决,但我发现其他报告似乎反映了单声道框架中的类似问题,并且已经解决。此外,我添加了代码以在连接蚂蚁之后从客户端发送一些“虚拟”数据,它似乎没有影响。

编辑 3:我最终在客户端收到此异常

System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.
at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) [0x0003a] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:430 
at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:256 
at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) [0x00360] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:533 

【问题讨论】:

    标签: c# linux ssl xamarin mono


    【解决方案1】:

    嗯......我几乎觉得回答这个问题很愚蠢,但我觉得其他人可能会因为同样的无知而陷入我的境地,所以希望这可以帮助具有类似架构的人。

    发生的事情是我创建了一个自签名证书并将其放在我的项目文件夹中,因此我的所有“服务器”实例都使用了相同的证书。发生的事情是,由于 SSL 会话缓存的一些内部缓存,在连接到一个设备后,它会缓存其信息,然后在下次连接时重新使用该信息。结果将是,由于自签名证书对所有设备使用相同的主机名,一旦它在连接到设备 A 后尝试重新连接到设备 B,它会尝试重新使用设备 A 的缓存信息(到目前为止据我所知)最初没有意义的原因是我可以一遍又一遍地连接和断开多个不同的 Windows 服务器,但只有在连接到 Mono 服务器时我才看到这个问题。结果,它似乎仍然是 Windows 或 Mono 的 SSLStream 实现中的一个错误(因为在完美的世界中,它们是相同的),但不幸的是我没有时间去挖掘反编译的源代码找到它。坦率地说,这可能无关紧要,因为我所做的是无论如何都打破了 SSL 连接的整个概念。

    最终,我创建了一个函数,使用 Mono.Security 以编程方式为每个设备生成唯一证书,然后提供一种机制为客户端提供唯一主机名(即使客户端直接连接到 IP 地址)。

    【讨论】:

      猜你喜欢
      • 2012-04-30
      • 2019-12-02
      • 2021-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多