使用基于主机名而不是 IP 地址的自签名证书保护 Python WebSocket
Posted
技术标签:
【中文标题】使用基于主机名而不是 IP 地址的自签名证书保护 Python WebSocket【英文标题】:Secure Python WebSocket with a self-signed Certificate based on a Hostname instead of an IP Address 【发布时间】:2020-09-23 17:39:28 【问题描述】:我正在使用python docs for WebSocket 中的示例进行安全 WebSocket 的简单 Python (3.8) 实现。这是在 Windows 10 计算机和连接到交换机/集线器的 Ubuntu 18.04.2 Linux 计算机之间。粗略的服务器和客户端代码如下:
服务器:
# WSS (WS over TLS) server example, with a self-signed certificate
import asyncio
import pathlib
import ssl
import websockets
async def hello(websocket, path):
name = await websocket.recv()
print(f"< name")
greeting = f"Hello name!"
await websocket.send(greeting)
print(f"> greeting")
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
private_key = pathlib.Path(__file__).with_name("private.key")
ssl_context.load_cert_chain(localhost_pem,private_key)
start_server = websockets.serve(
hello, "164.123.456.2", 1234, ssl=ssl_context)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
客户:
# WSS (WS over TLS) client example, with a self-signed certificate
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")
private_key = pathlib.Path(__file__).with_name("private.key")
ssl_context.load_verify_locations(localhost_pem, private_key )
async def hello():
uri = "wss://164.123.456.2:1234"
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())
我能够让这个实现与带有 IP 地址的主题备用名称 (SAN) 字段的自签名证书(使用 openssl 创建)一起使用。我想使用基于主机名而不是 IP 地址的证书。我在 SAN 证书字段中添加了“DNS Name =Hostname”,但这没有用。它导致以下错误:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: IP address mismatch, certificate is not valid for “164.123.456.2” (_ssl.c:1123)
这可能吗?应该在证书中添加哪些字段以使其工作?是否应该对 python 代码进行任何更改?
【问题讨论】:
【参考方案1】:uri = "wss://164.123.456.2:1234"
证书必须与 URL 中使用的域/IP 匹配,在本例中为 164.123.456.2
。如果要使用域,则必须在证书中包含域名并在 URL 中使用它。当然,域名必须解析为客户端系统上的正确 IP 地址。
【讨论】:
在 URL 中尝试主机名时,出现 python 错误,指出主机名无法解析为 IP 地址。如何确保在客户端系统上将域名解析为 IP 地址? @philaeagles:正常的方法是为此使用 DNS。如果这仅适用于单台机器,您可以在这台机器上edit the hosts file。以上是关于使用基于主机名而不是 IP 地址的自签名证书保护 Python WebSocket的主要内容,如果未能解决你的问题,请参考以下文章