Python调用使用自颁发证书的https接口

news/2024/12/1 18:39:58/

使用keytools或者openssl生成p12格式的KeyStore(包含SSL证书),并使用该证书和SpringBoot搭建了服务端的https接口,搭建过程参考HTTPS相关知识点介绍

接下来介绍如何在Pyhon中使用requests工具包调用服务端的https接口。

第1次尝试-直接调用

import requests
if __name__ == '__main__':LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success'REMOTE_SERVICE_URL = 'https://www.baidu.com/'print('\n\n-----request remote https-----')res = requests.get(REMOTE_SERVICE_URL)print(res.status_code)print('\n\n-----request local https-----')res = requests.get(LOCAL_SERVICE_URL)print(res.status_code)

运行结果:调用REMOTE_SERVICE_URL成功,调用LOCAL_SERVICE_URL抛出异常:ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1131)

结果分析:requests工具包进行SSL验证时依赖certifi工具包,certifi包安装目录下的cacert.pem文件中预置了可信任的根证书颁布机构清单,默认情况下只有清单中机构及其下层机构颁布的SSL证书可以通过验证。REMOTE_SERVICE_URL使用的SSL证书是正式CA机构颁布的,其根证书机构为:GlobalSign Root CA,该机构就在certifi包可信任的根证书CA机构清单中,所以调用REMOTE_SERVICE_URL成功。而LOCAL_SERVICE_URL使用的自颁布SSL证书,不在可信任机构清单中,所以验证失败抛出异常。

解决办法:一种是跳过SSL证书验证,一种是将自颁发证书的机构设置为可信任的。

第2次尝试-跳过SSL验证

根据requests的官方文档,虽然不推荐,但是可以通过设置请求参数verify=False来跳过SSL验证。

import requests
from requests.packages import urllib3
if __name__ == '__main__':LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success'REMOTE_SERVICE_URL = 'https://www.baidu.com/'# 屏蔽requests关闭SSL证书验证(verify参数设置为False)时的告警信息urllib3.disable_warnings()print('\n\n-----request remote https-----')res = requests.get(REMOTE_SERVICE_URL)print(res.status_code)print('\n\n-----request local https-----')res = requests.get(LOCAL_SERVICE_URL, verify=False)print(res.status_code)

第3次尝试-将自颁发证书的机构设置为可信任-临时设置

根据requests的官方文档,可以将请求参数verify设置为 CA_BUNDLE 文件的路径或者包含可信任 CA 证书文件的文件夹路径(如果 verify 设为文件夹路径,文件夹必须通过 OpenSSL 提供的 c_rehash 工具处理),这样也可以通过SSL证书验证。

根据博客What is a CA Bundle and Where to Find It?的说明,CA Bundle是包含根证书和中间证书的一个文件,由于自颁发SSL证书只有一层,所以自颁发的SSL证书就是CA Boundle文件。

requestsverify参数要求CA Bundle文件是文本格式,二进制的无法读取。下面介绍获取文本格式SSL证书的两种方法:

  1. 由于p12格式的KeyStore包含了SSL证书和私钥,所以需要从中提取SSL证书,采用openssl的python工具包将p12格式转换为pem格式
import os
from OpenSSL import crypto
​
def p12_to_pem(cert_name, pwd):pem_file_path = cert_name + '.pem'pem_file = open(pem_file_path, 'wb')p12_file_path = cert_name + '.p12'p12_file = crypto.load_pkcs12(open(p12_file_path, 'rb').read(), pwd)
​print(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12_file.get_privatekey()))print(crypto.dump_certificate(crypto.FILETYPE_PEM, p12_file.get_certificate()))
​pem_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12_file.get_privatekey()))pem_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, p12_file.get_certificate()))ca = p12_file.get_ca_certificates()if ca is not None:for cert in ca:pem_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))pem_file.close()return pem_file_path
​
if __name__ == '__main__':root_path = 'E:\dataPython\data\cert'cert_pem_file_path = p12_to_pem(os.path.join(root_path, 'baeldung'), b'****')

生成pem格式的SSL证书文件baeldung.pem内容如下:其中PRIVATE KEY其实不是SSL证书的内容,删除后也不影响证书验证。

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCN1bHqnX4kceSh
wSlb4s8X7Hz+581Kyq2tPDBSwqe6b9SmC5Hq0m8EbsChy/OwM9FrZZF9bOdPHHUM
sCtl3EEmc0fHylHqBT9/JWM=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIEZacX2zANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJD
TjESMBAGA1UECBMJZ3Vhbmdkb25nMREwDwYDVQQHEwhzaGVuemhlbjENMAsGA1UE
9o2PulnUgwok+63gcbkCA1In7tz+qylx/bhz8qT0eI6WpsPYc0Y=
-----END CERTIFICATE-----
  1. 除了使用openssl将p12转换为pem格式的SSL证书外,可以使用浏览器功能导出证书。在浏览器访问服务端的https接口后,按以下步骤即可导出cer格式的SSL证书。

导出的SSL证书文件baeldung.cer内容如下:只有证书内容,没有PRIVATE KEY。

-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIEZacX2zANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJD
TjESMBAGA1UECBMJZ3Vhbmdkb25nMREwDwYDVQQHEwhzaGVuemhlbjENMAsGA1UE
9o2PulnUgwok+63gcbkCA1In7tz+qylx/bhz8qT0eI6WpsPYc0Y=
-----END CERTIFICATE-----

最后设置requestsverify为CA BUNDLE文件路径来解决证书验证不通过的问题,用pem或cer格式的都可以。

import requests
from requests.packages import urllib3
if __name__ == '__main__':LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success'REMOTE_SERVICE_URL = 'https://www.baidu.com/'print('\n-----request remote https-----')res = requests.get(REMOTE_SERVICE_URL)print(res.status_code)print('\n-----request local https-----')res = requests.get(LOCAL_SERVICE_URL, verify='E:/dataPython/data/cert/baeldung.pem')print(res.status_code)res = requests.get(LOCAL_SERVICE_URL, verify='E:/dataPython/data/cert/baeldung.cer')print(res.status_code)

注:对于https://www.baidu.com/其SSL证书有3层,所以仅仅导出某一层的SSL证书是不能作为CA BUNDLE文件的,否则反而会报错。必须将3层证书按最底层到最高层(ROOT)的顺序拷贝到1个文件后,该文件才能作为CA BUNDLE文件。即按照博客What is a CA Bundle and Where to Find It?所说的操作。

第4次尝试-将自颁发证书的机构设置为可信任-永久设置

根据第1次尝试的结果分析,证书校验时从certifi包安装目录下的cacert.pem文件获取可信任的根证书颁发机构清单,那我们可以把我们自颁发的证书内容追加到cacert.pem文件来一次性解决SSL证书验证问题。追加内容后的cacert.pem文件如下:

# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
# Label: "GlobalSign Root CA"
# Serial: 4835703278459707669005204
# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----
​
# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA
# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA
# Label: "HARICA TLS ECC Root CA 2021"
# Serial: 137515985548005187474074462014555733966
# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0
# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48
# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01
-----BEGIN CERTIFICATE-----
MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw
nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
-----END CERTIFICATE-----
​
#省略其他ROOT CA
​
# SelfSigned 
-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIEZacX2zANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJD
TjESMBAGA1UECBMJZ3Vhbmdkb25nMREwDwYDVQQHEwhzaGVuemhlbjENMAsGA1UE
9o2PulnUgwok+63gcbkCA1In7tz+qylx/bhz8qT0eI6WpsPYc0Y=
-----END CERTIFICATE-----
​

再次运行第1次尝试的代码来调用https借口,访问都正常。

总结

第2、3、4次尝试中使用的三种解决方法,推荐采用第3次尝试使用的设置verify参数为CA BUNDLE文件路径,安全性更好。


http://www.ppmy.cn/news/237277.html

相关文章

Python 获取网站证书有效期

Python获取网站证书有效期 Python获取网站证书有效期python:OpenSSL和sslpythonshell:subprocess和curl Python获取网站证书有效期 由于某些原因,需要验证网站证书有效期,从而做出响应的措施来避免一些特殊情况的出现。 python&…

python 指定证书验证_如何在python中验证SSL证书?

我需要验证我的自定义CA签署了证书.使用OpenSSL命令行实用程序很容易做到: # Custom CA file: ca-cert.pem # Cert signed by above CA: bob.cert $openssl verify -CAfile test-ca-cert.pem bob.cert bob.cert: OK 但是我需要在Python中做同样的事情,而且我真的不想…

python 支付宝证书 计算SN 序列号

网上没看到有python写的算支付宝公钥证书与根证书序列号得,只有java与php,我python怎么能没有呢 整上! 安装pyOpenSSL pip install pyOpenSSL # codingutf-8 # author wangdada import OpenSSL import hashlib import redef md5(string):re…

python 证书-python+证书

广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! redirect:根据路由跳转页面render_template:找到并返回html页面,默认文件夹是tem…

python 证书-python requests证书问题解决

用requests包请求https的网站时,我们偶尔会遇到证书问题。也就是常见的SSLerror,遇到这种问题莫慌莫慌。 这里没有找到合适的网站去报SSL证书的错误,所以就假装请求了一个https的网站,然后给报了SSLerror了,然后下面是…

pythonrequests证书_python requests证书问题解决

用requests包请求https的网站时,我们偶尔会遇到证书问题。也就是常见的SSLerror,遇到这种问题莫慌莫慌。 这里没有找到合适的网站去报SSL证书的错误,所以就假装请求了一个https的网站,然后给报了SSLerror了,然后下面是…

工信部python证书多少钱_python requests SSL证书问题

错误信息如下: requests.exceptions.SSLError: ("bad handshake: Error([(SSL routines, tls_process_server_certificate, certificate verify failed)],)",) python做爬虫,对于有的网站,需要验证证书,比如&#xff1a…

python证书过期_简单python脚本监控SSL证书到期提醒

随着https的普及,或者说被强制使用,需要维护的SSL证书越来越多,而且由于各种原因吧,需要在各种不同的平台申请维护证书,时间长了,总有证书忘记续签 有些使用了letsencrypt自动续签,但是某些原因…