簡體   English   中英

總是從ssl socket消息中分兩部分接收(c#client,python3 server)

[英]Always receive from ssl socket message in two parts (c# client, python3 server)

我正在c#(windows)中編寫ssl客戶端,在python 3(linux)中編寫ssl服務器。 我的問題是,我發送這個(c#):

byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
byte[] empty = Encoding.UTF8.GetBytes("Baa");
sslStream.Write(empty);
sslStream.Write(messsage);
sslStream.Flush();

我在python服務器中得到這個:

b'B'
b'aa'
b'H'
b'ello from the client.<EOF>'

我的消息分為兩部分,第一部分總是有1個字節,第二部分有其余部分。

只有當我嘗試從我的客戶端發送到我的服務器時才會出現問題。 當我用openssl( openssl s_client -connect 172.22.22.1:10443openssl s_server -accept 10443 -cert server.cert -key server.key )測試它時,它會打印正確的消息。

我的ssl服務器:

#!/usr/bin/python

import socket, ssl

HOST, PORT, CERT = '0.0.0.0', 10443, 'server.pem'

def handle(conn):
  while True:
      data = conn.recv()
      if not data:
          break
      else:
          print(data)

def main():
  sock = socket.socket()
  sock.bind((HOST, PORT))
  sock.listen(5)
  context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
  context.load_cert_chain(certfile=CERT)
  while True:
    conn = None
    ssock, addr = sock.accept()
    try:
      conn = context.wrap_socket(ssock, server_side=True)
      handle(conn)
    except ssl.SSLError as e:
      print(e)
    finally:
      if conn:
        conn.close()
if __name__ == '__main__':
  main()

我的客戶:

class Program
    {
        public static bool ValidateServerCertificate(
              object sender,
              X509Certificate certificate,
              X509Chain chain,      
              SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
                return true;

            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
            return false;
        }
        public static void RunClient(string machineName, string serverName)
        {
            TcpClient client = new TcpClient(machineName, 10443);
            Console.WriteLine("Client connected.");
            SslStream sslStream = new SslStream(
                client.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),
                null
                );
            try
            {
                sslStream.AuthenticateAsClient(serverName, new X509CertificateCollection(), SslProtocols.Tls, true);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
                client.Close();
                return;
            }

            byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
            byte[] empty = Encoding.UTF8.GetBytes("Baa");
            sslStream.Write(empty);
            sslStream.Write(messsage);
            sslStream.Flush();
            client.Close();
            Console.WriteLine("Client closed.");
        }        

        public static int Main(string[] args)
        {
            string serverCertificateName = "test";
            string machineName = "172.22.22.1";

            RunClient(machineName, serverCertificateName);
            return 0;
        }
    }

我的消息分為兩部分......

在TCP上使用TLS時,沒有消息的概念。 它只是一個非結構化數據流,任何結構(如消息邊界)都必須由此流上的應用程序協議添加,與普通TCP相同。

雖然.NET客戶端的行為很奇怪(而且它似乎是由客戶端而不是服務器引起的),但也可能是recv會同時返回兩個“消息”,返回一條短消息但是更大的消息件或類似的。 因此,您的代碼和應用程​​序協議必須考慮到這一點,因為它不會假設recv隱式處理您的消息邊界。

分別發送傳出數據的第一個字節的做法稱為1 / n-1拆分 ,最近的客戶端實現是為了緩解SSL / TLS漏洞CVE-2011-3389 ,也稱為“BEAST”。

發送方使用的.Net / OS庫執行此緩解,底層技巧的結果顯然泄漏到Python代碼中的應用程序級別。

可以通過使用不同的協議或密碼套件來避免這種情況。 但正如Steffen已經說過的那樣,SSL代碼必須期望數據以任何方式分裂並仍然正確處理它,因此解決方案是實現一些消息框架(特殊的“消息結束”字符,發送長度之前數據,......)在不依賴實施細節和運氣的情況下知道它們的結束位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM