使用 python 和 http.client 在 post 请求中包含证书的示例

Example of including a certficate in a post request with python and http.client

我正在尝试 POST xml 使用 python 的网站。我必须包含证书,但不确定如何执行此操作。在我的电脑本地指定证书的文件路径是否足够?

任何人都可以向我展示如何在请求中包含证书的示例吗?

import http.client, urllib.parse

xml="""<?xml version="1.0" encoding="UTF-8"?>
<home>
  <bathroom>1</bathroom>
  <kitchen>1</kitchen>
  <street>515</street>
</home>);"""

headers = {"username": "password"}

conn = http.client.HTTPSConnection("someurl.com", cert_file="D:\Users\Username\certificate.p12")
conn.request("POST", "/to/this/place", xml, headers)
response = conn.getresponse()
print(response.status, response.reason)
data = response.read()
print(data)
conn.close()

如果您没有使用自签名证书并且您的证书是由相对值得信赖的机构签署的(即互联网上的正常 someurl.com),那么您应该在制作您的证书时使用系统 CA 证书连接。

在 Python 3.4.3 或更高版本中,您可以通过调用 HTTPSConnection() 而无需为其提供证书文件或上下文来做到这一点。

如果您使用的是自签名证书,那么您可以从本地硬盘加载证书。您需要将私钥包含在证书文件中或指定为密钥文件。如果在您的环境中完全可行,您还需要进行主机验证。请参阅 verify_modecheck_hostname 选项。

import http.client
import ssl

password = input("Key password (enter for none):") or None

xml = """<?xml version="1.0" encoding="UTF-8"?>
<home>
  <bathroom>1</bathroom>
  <kitchen>1</kitchen>
  <street>515</street>
</home>);"""

headers = {"username": "password"}

context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.load_cert_chain("cert.pem", "key.pem", password=password)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True

conn = http.client.HTTPSConnection("someurl.com", port=443, context=context)

conn.request("POST", "/to/this/place")
response = conn.getresponse()
print(response.status, response.reason)
data = response.read()
print(data)
conn.close()

我用它来避免让客户执行 pkcs12 到 PEM 的转换。基本上覆盖上下文 class 以允许它加载 pkcs12 文件。这适用于 python3

import requests
from OpenSSL import crypto

class Pkcs12Context(requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context):
    def __init__(self, method):
        super().__init__(method)
        p12 = crypto.load_pkcs12(open("/certs/client.p12", 'rb').read(), 'password')
        self.use_certificate(p12.get_certificate())
        self.use_privatekey(p12.get_privatekey())

# Monkey-patch the subclass into OpenSSL.SSL so it is used in place of the stock version
requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context = Pkcs12Context

r = requests.get('https://example.com')

print(r.text)