umg*_*ren 1 python sockets ssl python-3.x
我使用通过以下命令生成的自签名证书:
sudo make-ssl-cert generate-default-snakeoil
Run Code Online (Sandbox Code Playgroud)
并将其复制到我的主目录。如果我在服务器端运行以下命令:
from socket import socket, AF_INET, SOCK_STREAM
import ssl
def main():
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.verify_mode = ssl.CERT_REQUIRED
context.load_cert_chain('/home/hfurmans/ssl-cert-snakeoil.pem', '/home/hfurmans/ssl-cert-snakeoil.key')
host = "myipaddress"
port = 5432
my_socket = socket(AF_INET, SOCK_STREAM)
my_socket.bind((host, port))
my_socket.listen(1)
my_socket = context.wrap_socket(my_socket, server_side=True)
conn, addr = my_socket.accept()
print("Connection from: " + str(addr))
data = conn.recv(1024).decode()
print(data)
print("from connected user: " + str(data))
data = str(data).upper()
print("sending: " + str(data))
conn.send(data.encode())
conn.close()
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
我替换了我的 IP 地址。但是它们在服务器和客户端上是相同的。这是客户端代码:
import socket
import ssl
hostname = "myipaddress"
context = ssl.create_default_context()
sock = socket.create_connection((hostname, 5432))
ssock = context.wrap_socket(sock, server_hostname=hostname)
print(ssock.version())
ssock.send("test")
Run Code Online (Sandbox Code Playgroud)
如果我运行这两个脚本,我会收到以下错误。这是客户端错误:
bash-3.2$ python3 client.py
Traceback (most recent call last):
File "client.py", line 8, in <module>
ssock = context.wrap_socket(sock, server_hostname=hostname)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 500, in wrap_socket
return self.sslsocket_class._create(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1040, in _create
self.do_handshake()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1108)
Run Code Online (Sandbox Code Playgroud)
这是服务器错误:
Traceback (most recent call last):
File "server.py", line 27, in <module>
main()
File "server.py", line 16, in main
conn, addr = my_socket.accept()
File "/usr/lib/python3.6/ssl.py", line 1125, in accept
server_side=True)
File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
_context=self, _session=session)
File "/usr/lib/python3.6/ssl.py", line 817, in __init__
self.do_handshake()
File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
self._sslobj.do_handshake()
File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:852)
Run Code Online (Sandbox Code Playgroud)
自签名证书是一种假装 CA 是证书本身的技巧。所以我们必须事先向客户端提供这个证书,以便在遇到它时信任它。
在客户端,创建 SSL 上下文后,我尝试了类似
context.load_verify_locations('/home/hfurmans/ssl-cert-snakeoil.pem')
Run Code Online (Sandbox Code Playgroud)
它奏效了。
(https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_verify_locations)
我只需要context.verify_mode = ssl.CERT_REQUIRED在服务器中删除,因为我没有为我的客户提供自己的证书,但这不是您的问题中报告的问题。
当然,要使所有这些工作正常进行,您的证书必须具有正确的通用名称。
如果客户端连接到myipaddress(作为主机名),则证书的公用名也必须是myipaddress。