【问题标题】:Python3 Socket Programming with SSL errors?带有 SSL 错误的 Python3 套接字编程?
【发布时间】:2020-08-12 23:10:58
【问题描述】:

我只是在学习 Python 套接字编程和安全网络的基础知识。我已经在我的网络上连接了两个虚拟机,我想看看 Wireshark 中加密和非加密消息之间的区别。所以,我按照这些教程https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309https://docs.python.org/2/library/ssl.html#server-side-operationhttps://docs.python.org/3.8/library/ssl.html#server-side-operation 为我的服务器 VM 设置了一些 openSSL 证书,并将 rootCA 证书复制到我的客户端 VM。

这些是我创建自签名证书时遵循的命令:

openssl genrsa -des3 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256

当它询问通用名称时,我给了它我服务器的 IP,即 172.25.1.5。

但是,当我尝试运行服务器和客户端 python 脚本时,出现以下错误:

$ python3 server.py 
what is host? 172.25.1.5
server bound.
server listening
Accepted conn from: ('172.25.1.4', 59592)
Traceback (most recent call last):
  File "server.py", line 32, in <module>
    connstream = context.wrap_socket(conn,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)

在客户端,我看到了:

$ python3 client.py 
Traceback (most recent call last):
  File "client.py", line 19, in <module>
    s.connect((host,port))
  File "/usr/lib/python3.6/ssl.py", line 1109, in connect
    self._real_connect(addr, False)
  File "/usr/lib/python3.6/ssl.py", line 1100, in _real_connect
    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: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)

这是我的服务器和客户端代码:

import os, socket, ssl

# host and port
host = "172.25.1.5" # my VM ip
port = 1234
print("what is host? " + host)

# create context for socket (with ssl security)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="server.crt",keyfile="server.key")

# create socket and bind the socket to a tuple of host,port
s = socket.socket()
s.bind((host,port))
print("server bound.")

# listen for connections. The normal max is 5. The slides have 1.
print("server listening")
s.listen(1)

# accept connection
conn,address = s.accept()
print("Accepted conn from: " + str(address))

# give connection context
connstream = context.wrap_socket(conn,server_side=True)
#connstream = conn
print("wrapped socket.")

# receive data loop
# breaks if no data received
while True:
    data = connstream.recv(1024).decode()
    if not data:
        break
    print("received from client: " + str(data))
    # echo back
    connstream.send(data.encode())
connstream.shutdown(socket.SHUT_RDWR)
connstream.close()
conn.close()

这是我在不同 VM 上的客户端脚本:

import os, socket, ssl

# get context
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_verify_locations("rootCA.crt")
# define host and port
host = "172.25.1.5" #ip of linked clone
port = 1234

# make socket and connect to tuple host,port. Wrap socket in context
s = context.wrap_socket(socket.socket(socket.AF_INET),server_hostname=host)
s.connect((host,port))

cert = s.getpeercert()
print("What is cert? " +str(cert))
print("\n\n")
# get input
msg = input("out: ")

# Receive msg loop and send loop
while msg.lower().strip() != '':
    s.send(msg.encode())
    data = s.recv(1024).decode()

    print("In: " + data)

    msg = input("Out: ")

s.close()

我被困住了。我已确保我的代码遵循示例。如何解决这些错误?我有什么遗漏吗?

感谢任何帮助或解释。我还在学习。

【问题讨论】:

  • 如果您只是尝试使用 SSL 并学习基础知识,那么您肯定不想与客户端证书有任何关系。
  • 我只有服务器证书。客户端只能访问我用来创建服务器密钥和证书的自签名证书。
  • 我正在学习一个教程,这就是它的代码 sn-p 并解释说,如果我只有客户端会检查其有效性的服务器证书,它应该可以工作。服务器不应该检查客户端。
  • 请参阅docs.python.org/3.8/library/ssl.html#ssl.SSLContext.verify_mode 默认情况下它是 CERT_REQUIRED,因此服务器将向客户端询问证书,然后它不知道签署此证书的 CA,因此来自 TLS CA 错误服务器端,这意味着客户端证书未按照客户端报告的方式进行验证。
  • @JosephSible-ReinstateMonica Purpose.CLIENT_AUTH 完全没问题,请参阅 docs.python.org/3.8/library/ssl.html#server-side-operation 。问题在于verify_mode 默认设置。

标签: python sockets ssl


【解决方案1】:

按照 Patrick Mevzek 在 cmets 中的建议,我尝试更改线路

context.load_cert_chain(certfile="server.crt",keyfile="server.key")

context.load_cert_chain(certfile="rootCA.crt",keyfile="rootCA.key")

这行得通,这告诉我在创建 server.crt 和 server.key 时出了点问题。所以,我只是简单地删除了服务器 VM 中的 server.key、server.csr 和 server.crt,然后使用

openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256

重新创建后,我可以使用 server.crt 和 server.key 作为 certfile 和 keyfile。

将我的假 CA 设置与 server.crt 一起使用,或者直接使用 rootCA for SSL 来加密我的消息,并且使用 Wireshark 也验证了这一点。

感谢大家的帮助,我希望这个答案可以帮助其他在玩套接字编程和 SSL 时遇到这个问题的人。

【讨论】:

    猜你喜欢
    • 2014-08-17
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多