Python SSL套接字服务器SSLV3_ALERT_CERTIFICATE_UNKNOWN问题

3
我正在编写一个带有SSL的Python套接字服务器,但在SSL握手期间遇到证书未知错误。
我使用openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes命令创建了私钥和证书。
该服务器旨在在我的PC的内部网络(WiFi下)运行,并且用户将使用浏览器联系我的PC IP地址。因此,我没有向任何CA注册此证书,而且我认为在我的情况下这并非强制要求。
以下是更多详细信息...

echoserver.py

import socket
import ssl
import threading
class echoserver:
    def __init__(self,i,p):
        self.ip=i
        self.port=p
    def handler(self,c,a):
        msg=c.recv(1024)
        c.send(msg)
    def serve(self):
        echoserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        echoserver = ssl.wrap_socket(echoserver, keyfile='keys/key.pem', certfile='keys/cert.pem', server_side=True)
        echoserver.bind((self.ip, self.port))
        echoserver.listen()
        while True:
            (c,a)=echoserver.accept()
            threading.Thread(target=self.handler, args=(c,a)).start()

es=echoserver('192.168.43.124',443) #My PC's ip assigned under wifi network
es.serve()

#Connecting from mobile phone within same network as https://192.163.43.124

服务器在 SSL 握手期间出现错误

        self._sslobj.do_handshake()      
    ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:1108)

我尝试了以下方法:

  • 在wrap_socket函数中添加cert_reqs=ssl.CERT_NONE和ca_certs="/location/to/keys"参数。
    似乎没有起作用。我认为这些选项是针对客户端的。
  • 在wrap_socket函数中添加do_handshake_on_connect=False
    在Chrome中,当连接服务器时抛出相同的错误并关闭线程/连接时。而且Chrome似乎会立即再次发送相同的连接请求,第二个请求运行得非常顺利!!
    在Firefox中,第一次连接关闭时出现相同的错误,并且没有第二个请求。
  • 将证书中的通用名称分配为IP地址
    无效。
  • 在ietf规范here中检查certificate_unknown错误。除了这个解释之外,它没有提供任何线索certificate_unknown:在处理证书时出现了其他(未指定的)问题,使其不可接受。

我注意到的另一件事是,如果我以与下面相同的方式使用内置的ThreadedHTTPServer,它可以完美地工作,没有我上面提到的任何问题。

httpd = self.ThreadedHTTPServer((self.ip, self.port), self.handler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='keys/key.pem', certfile='keys/cert.pem', server_side=True)

我不确定为什么会发生这种情况,也不知道该如何处理。而且不确定内置的服务器模块是如何正常工作的。
感激任何线索。谢谢。
以下Python内置的HTTPServer与ssl一起正常工作,没有显示任何错误。不确定为什么?
import ssl
from http.server import HTTPServer, BaseHTTPRequestHandler

class requesthandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type","text/html")
        self.end_headers()
        self.wfile.write("<html><body>It works</body></html>".encode('utf8'))

httpd = HTTPServer(('192.168.43.124', 443), requesthandler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='keys/key.pem', certfile='keys/cert.pem', server_side=True)
httpd.serve_forever()
1个回答

6
ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:1108)

这意味着客户端(浏览器)不信任您的证书,因为它是由一个未知实体颁发的。如果您想使用自签名证书,则必须明确导入这些证书以供您要使用的所有客户端信任。

这是无法避免的。TLS中的证书是为了确保连接是与预期的服务器进行的,而不是某个中间人声称是预期的服务器。如果客户端信任任意证书,则还会信任中间人攻击者创建的证书。

下面 Python 内置的 HTTPServer 可以正常使用 SSL,没有显示任何错误。不确定原因?

浏览器仍然会抱怨。 唯一的区别是服务器捕获异常,因此不会崩溃,而是继续运行。您可以在代码中做同样的事情:

    while True:
        try:
            (c,a)=echoserver.accept()
            threading.Thread(target=self.handler, args=(c,a)).start()
        except:
            pass # ignore error

谢谢@Steffen。非常感谢。你能解释一下,这对于内置的服务器模块(如ThreadedHTTPServer)是如何正常工作的吗? - undefined
@Liju:除非您在浏览器中明确跳过了安全警告,否则它不应该与自签名证书和ThreadedHTTPServer一起工作。 - undefined
谢谢@Steffen。我正在重新表达我的问题。作为一个测试,我尝试创建一个新的ThreadedHTTPServer实例,并使用相同的密钥对其进行ssl_wrapped,并在PC上启动它。现在我可以从移动浏览器连接。服务器没有抛出证书错误(由浏览器发送)。这就是我想知道的,它是否设计成以某种方式抑制和忽略浏览器中的这些错误并继续运行? - undefined
1
@Liju:我在浏览器中明确地收到了NET::ERR_CERT_AUTHORITY_INVALID的错误提示,这是预料之中的。唯一不同的是,由于你使用的类捕获了错误,所以服务器并没有崩溃。然而,问题仍然存在,即证书未被客户端信任。为了访问内容,需要明确地跳过警告。 - undefined
是的。在浏览器端,如果我点击“接受风险”,它会继续执行。但是在服务器端,Python内置的HTTPServer即使捕获了错误,仍然可以继续工作,而我的套接字程序却终止了。也许我漏掉了一个非常基本的东西。您能解释一下如何在服务器端实现容错吗? - undefined
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接