HTTPS认证过程和SSLError bad handshake原因分析
问题
项目上部署多个系统,相互间请求接口时经常遇到如下报错:
response = requests.post(url, data, headers, verify=True, timeout=300)
HTTPSConnectionPool(host='xx.net', port=443): Max retries exceeded with url: /xx/api/rest (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
分析
1. HTTPS建立连接
https建立连接时,在http三次握手建立连接后,还有TLS握手过程,如下图所示(参考链接)
2. HTTPS单向认证和双向认证
1. 认证方向与核心目标
1.1单向认证(One-way Authentication)
方向:仅客户端验证服务器身份,服务器不验证客户端身份。
目标:确保客户端访问的是合法的服务器,防止中间人攻击(如钓鱼网站)。
典型场景:普通网站(如电商、社交媒体)、API接口等。
1.2双向认证(Two-way/Mutual TLS Authentication)
方向:客户端和服务器互相验证身份,双方均需提供有效证书。
目标:在单向认证基础上,进一步确保客户端是授权的合法用户,防止未授权访问。
典型场景:企业内网、金融系统、物联网设备等高安全需求场景。
2. 流程差异
2.1单向认证流程
客户端发起请求:客户端向服务器发送HTTPS连接请求。
服务器返回证书:服务器发送其SSL证书(含公钥)给客户端。
客户端验证证书:客户端通过内置的CA证书库验证服务器证书的合法性(如域名匹配、有效期、CA签名等)。
密钥协商:客户端生成对称密钥,用服务器公钥加密后发送给服务器,完成加密通信。
2.2双向认证流程
在单向认证基础上增加以下步骤:
服务器要求客户端证书:服务器在验证自身证书后,向客户端发送CertificateRequest消息,要求客户端提供证书。
客户端发送证书:客户端提交自己的SSL证书(含公钥)。
服务器验证客户端证书:服务器验证客户端证书的合法性(如CA签名、有效期等)。
双向密钥协商:双方基于彼此的公钥生成共享密钥,完成加密通信。
3. Nginx配置文件
# 路径
/etc/nginx/xx.conf
### HTTPS服务
server {
listen 443 ssl;
server_name 内网域名/公网域名;
## HTTPS配置
# 如果在公网环境部署,需使用CA授权的证书
ssl_certificate _.xx.net.crt;
ssl_certificate_key _.xx.net.key;
# 如果在内网环境部署,需使用系统自行授权的证书(自定义根证书为root.crt)
ssl_certificate default.server.crt;
ssl_certificate_key default.server.nopassword.key;
# 如果在内网环境部署,并开启HTTPS双向认证,需开启如下配置
ssl_client_certificate root.crt;
ssl_verify_depth 1;
ssl_verify_client on;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
...
}
4. 请求代码
# 如果系统部署在内网,需要发送根证书供nginx校验
response = requests.post(url, data, headers, verify='root.crt file path', cert='xx', timeout=300)
# 如果系统部署在外网,无需发送根证书,由CA校验
response = requests.post(url, data, headers, timeout=300)
示意图
5. SSLError bad handshake原因
公网和内网两种部署情况下,python代码与nginx配置的ssl_certificate、ssl_certificate_key不对应。
其他原因,如网站证书过期等,此处不作分析。
更多推荐



所有评论(0)