如何检测通过TLS安全套接字发送数据的尝试失败?

本文关键字:数据 套接字 失败 安全套 安全 何检测 检测 TLS | 更新日期: 2023-09-27 18:09:41

这个示例应用程序通过TLS安全套接字创建一个客户端-服务器连接,并通过它发送一些数据:

    static void Main(string[] args)
    {
        try
        {
            var listenerThread = new Thread(ListenerThreadEntry);
            listenerThread.Start();
            Thread.Sleep(TimeSpan.FromSeconds(1));
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            socket.Connect("localhost", Port);
            var rawStream = new NetworkStream(socket);
            using (var sslStream = new SslStream(rawStream, false, VerifyServerCertificate))
            {
                var certificate = new X509Certificate(CertsPath + @"test.cer");
                var certificates = new X509CertificateCollection(new[] { certificate });
                sslStream.AuthenticateAsClient("localhost", certificates, SslProtocols.Tls, false);
                using (var writer = new StreamWriter(sslStream))
                {
                    writer.WriteLine("TEST");
                    writer.Flush();
                    Thread.Sleep(TimeSpan.FromSeconds(10));
                }
            }
            socket.Shutdown(SocketShutdown.Both);
            socket.Disconnect(false);
            Console.WriteLine("Success! Well, not really.");
        }
        catch (Exception exc)
        {
            Console.WriteLine(exc);
        }
    }
    private static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        return true;
    }
    static void ListenerThreadEntry()
    {
        try
        {
            var listener = new TcpListener(IPAddress.Any, Port);
            listener.Start();
            var client = listener.AcceptTcpClient();
            var serverCertificate = new X509Certificate2(CertsPath + @"'test.pfx");
            var sslStream = new SslStream(client.GetStream(), false);
            sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, false);
            client.Close();  // terminate the connection
            using (var reader = new StreamReader(sslStream))
            {
                var line = reader.ReadLine();
                Console.WriteLine("> " + line);
            }
        }
        catch (Exception exc)
        {
            Console.WriteLine(exc);
        }
    }

诀窍是在握手后立即从服务器端终止连接。问题是客户端对此一无所知;我希望客户端在试图通过关闭的连接发送数据时引发异常,但它没有。
因此,问题是:当连接中断并且数据没有真正到达服务器时,我如何检测这种情况?

如何检测通过TLS安全套接字发送数据的尝试失败?

不可能知道在TCP模型下哪些数据包已经到达。TCP是一个面向流的协议,而不是面向包的协议;也就是说,它的行为就像一个双向管道。如果你写7个字节,然后写5个字节,有可能另一端一次只得到12个字节。更糟糕的是,TCP的可靠交付只保证如果数据到达,它将以正确的顺序进行,而不会重复或重新排列,如果数据没有到达,则将重新发送。

如果连接意外断开,TCP不能保证您确切地知道丢失了哪些数据,也不能合理地提供该信息。客户端唯一知道的是"我从来没有收到字节数N的确认[大概也没有收到前N个字节的确认],尽管它们被重发了很多次。"这些信息不足以确定字节N(以及其他丢失的字节)是否到达服务器。有可能它们确实到达了,但在服务器能够确认它们之前,连接就断开了。也有可能他们根本就没有到达。TCP不能向您提供此信息,因为只有服务器知道它,而您已不再连接到服务器。

现在,如果您正确关闭套接字,使用shutdown(2)或. net等效,则飞行中的数据将尽可能通过,并且另一端将及时出错。一般来说,我们尝试确保双方都同意何时关闭连接。在HTTP中,使用Connection: Close头,在FTP中使用BYE命令,依此类推。如果一方意外关闭,它仍然可能导致数据丢失,因为关闭通常不会等待确认。