【问题标题】:Python SSL Verify Alternative DomainPython SSL 验证备用域
【发布时间】:2021-08-09 06:23:28
【问题描述】:

我打算通过 TLS 连接到远程主机 example.com,但我必须通过 DNS 名称为 example-proxy.com 的代理 IP 地址连接。

我无法控制 SSL 证书,也无法要求 example.com 的管理员将 example-proxy.com 添加到其证书的 SAN。

使用 example-prxoy.com 会导致 OpenSSL to error out,因为主机名与证书中的名称不匹配。如何将主机参数拆分为两个:(1)用于网络连接的域名和(2)用于证书验证的域名。

我没有资源来修改 OpenSSL 库,但我可以更改 Python 库。根据this doc,我本可以修改match_hostname 方法来实现此功能,但从Python 3.7+ 起不再可用。

询问

  1. 如何使用 Python 3.7+ 来指定主机名和证书名?
  2. 从安全的角度来看,我的实施怎么会出错?

【问题讨论】:

  • 最佳实践是创建一个自签名 CA 证书(从技术上讲,它们都是自签名的)并使用该 CA 为 example.com 签署证书并将其安装在 example-proxy.com 上。然后您可以将 CA 安装到运行 Python 代码的计算机的信任库中。
  • 我应该补充一点,我也无权访问 example-proxy.com。此外,example-proxy 是一个 L3 TCP/IP 代理,它不干预 TLS 握手。我也没有网络管理员访问权限,也无法更改 DNS 记录。
  • 我明白了,是的,使用 TCP 代理你真的什么都做不了。您使用的是requests 还是普通的urllib?看看this answer 是否有帮助。
  • 我直接使用ssl包中的SSLSocket。

标签: python security ssl openssl tls1.3


【解决方案1】:

只需为 TCP 连接和 TLS 握手提供不同的主机名,即在 wrap_socket 中设置 server_hostname。为此修改the example from the official documentation

import socket
import ssl

tls_hostname = 'www.example.com'
context = ssl.create_default_context()

with socket.create_connection(('127.0.0.1',8443)) as sock:
    with context.wrap_socket(sock, server_hostname=tls_hostname) as ssock:
        print(ssock.version())

这将连接到 ('127.0.0.1',8443),但会与 www.example.com 进行 TLS 握手。 请注意,这将使用tls_hostname 进行 TLS 握手中的 SNI 扩展和验证证书。但这似乎是您所需要的,基于您的问题:连接到 IP:port 但使用特定主机名进行 TLS 握手和验证。

【讨论】:

  • 谢谢!有效。您是否发现此配置可能出现任何潜在的安全漏洞?
  • @John:主机名验证的重点是证书与预期的主机名匹配,以防止中间人攻击。这里的期望是明确定义的。这意味着不存在由此引入的安全问题。
猜你喜欢
  • 2015-06-01
  • 2017-02-06
  • 2010-11-08
  • 2022-08-24
  • 2021-12-10
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
  • 2018-12-25
相关资源
最近更新 更多