How to create Python secure websocket client request?
我的Python安全websocket客户端代码给了我以下例外:
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
我已经创建了我的私人证书和签名证书,但是我无法使用Python脚本按如下方式连接到它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import json from websocket import create_connection class subscriber: def listenForever(self): try: # ws = create_connection("wss://localhost:9080/websocket") ws = create_connection("wss://nbtstaging.westeurope.cloudapp.azure.com:9090/websocket") ws.send("test message") while True: result = ws.recv() result = json.loads(result) print("Received '%s'" % result) ws.close() except Exception as ex: print("exception:", format(ex)) try: subscriber().listenForever() except: print("Exception occured:") |
我的带有龙卷风的python中的https / wss服务器脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import tornado.web import tornado.websocket import tornado.httpserver import tornado.ioloop import os import ssl ssl_root = os.path.join(os.path.dirname(__file__), 'ssl1_1020') class WebSocketHandler(tornado.websocket.WebSocketHandler): def check_origin(self, origin): return True def open(self): pass def on_message(self, message): self.write_message("Your message was:" + message) print("message received:", format(message)) def on_close(self): pass class IndexPageHandler(tornado.web.RequestHandler): def get(self): self.render("index.html") class Application(tornado.web.Application): def __init__(self): handlers = [ (r'/', IndexPageHandler), (r'/websocket', WebSocketHandler), ] settings = { 'template_path': 'templates' } tornado.web.Application.__init__(self, handlers, **settings) ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_ctx.load_cert_chain(ssl_root+"/server.crt", ssl_root +"/server.pem") if __name__ == '__main__': ws_app = Application() server = tornado.httpserver.HTTPServer(ws_app, ssl_options=ssl_ctx,) server.listen(9081,"0.0.0.0") print("server started...") tornado.ioloop.IOLoop.instance().start() |
创建SSL签名证书的步骤:
1 2 3 4 | openssl genrsa -des3 -out server.key 1024 openssl rsa -in server.key -out server.pem openssl req -new -nodes -key server.pem -out server.csr openssl x509 -req -days 365 -in server.csr -signkey server.pem -out server.crt |
终于找到了解决方案,我在连接到安全Web套接字URL的同时更新了python客户端脚本,以忽略证书请求,如下所示:
1 2 3 4 5 | import ssl import websocket ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE}) ws.connect("wss://xxx.com:9090/websocket") |
如果将来有人好奇,为什么wss python服务器会失败是因为龙卷风文档中的此内容:
When using a secure websocket connection (wss://) with a self-signed certificate, the connection from a browser may fail because it wants to show the"accept this certificate" dialog but has nowhere to show it. You must first visit a regular HTML page using the same certificate to accept it before the websocket connection will succeed.
仅尝试以下方法进行测试。 以下是高度不安全的克鲁格:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import asyncio, ssl, websockets #todo kluge #HIGHLY INSECURE ssl_context = ssl.SSLContext() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE #HIGHLY INSECURE #todo kluge uri ="wss://myAwesomeSSL.wss.kluge" async with websockets.connect(uri, ssl=ssl_context) as websocket: greeting = await websocket.recv() print(f"< {greeting}") |
对我来说,忽略错误不是一种选择,我必须使用我的自签名证书:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import asyncio import pathlib import ssl import websockets ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) localhost_pem = pathlib.Path(__file__).with_name("localhost.pem") ssl_context.load_verify_locations(localhost_pem) async def hello(): uri ="wss://localhost:8765" async with websockets.connect( uri, ssl=ssl_context ) as websocket: name = input("What's your name?") await websocket.send(name) print(f"> {name}") greeting = await websocket.recv() print(f"< {greeting}") asyncio.get_event_loop().run_until_complete(hello()) |
在websocket存储库的examples文件夹中找到了它。
压力
我将其从