[英]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:10443
和openssl 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.