我有一个小型 Web 服务器,其中装有 Python (v3.6)、Flask (v1.1.1) 和 NginX (v1.16.1)。我已从 获取并设置了 SSL 证书sslforfree.com
。当我使用任何浏览器访问页面时,一切正常,但我无法使用 Python 脚本和请求库访问它:
import requests
print(requests.get('https://www.some-project.com'))
Traceback (most recent call last):
File "/anaconda3/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 441, in wrap_socket
cnx.do_handshake()
File "/anaconda3/lib/python3.6/site-packages/OpenSSL/SSL.py", line 1907, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "/anaconda3/lib/python3.6/site-packages/OpenSSL/SSL.py", line 1639, in _raise_ssl_error
_raise_current_error()
File "/anaconda3/lib/python3.6/site-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 601, in urlopen
chunked=chunked)
File "/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 346, in _make_request
self._validate_conn(conn)
File "/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 850, in _validate_conn
conn.connect()
File "/anaconda3/lib/python3.6/site-packages/urllib3/connection.py", line 326, in connect
ssl_context=context)
File "/anaconda3/lib/python3.6/site-packages/urllib3/util/ssl_.py", line 329, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "/anaconda3/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 448, in wrap_socket
raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/anaconda3/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 639, in urlopen
_stacktrace=sys.exc_info()[2])
File "/anaconda3/lib/python3.6/site-packages/urllib3/util/retry.py", line 388, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='www.some-project.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/aivanf/Desktop/some-project/py-API/test.py", line 55, in <module>
main()
File "/Users/aivanf/Desktop/some-project/py-API/test.py", line 49, in main
print(requests.get(MAIN_URL))
File "/anaconda3/lib/python3.6/site-packages/requests/api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/requests/api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/anaconda3/lib/python3.6/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/requests/adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='www.some-project.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
我尝试在不同的计算机上执行相同的操作,以更新 OpenSSL 和根证书,但没有任何帮助... 问题出在哪里?为什么所有浏览器都可以正常使用该网站,但 Python 却不行?如何解决?
此外,https://sslforfree.com
虽然它的证书与我的非常相似,但访问它本身却运行良好。因此,我猜问题出在我的 NginX 配置上:
这是我的 NginX 配置:
ssl_certificate /var/www/ssl/ca.crt;
ssl_certificate_key /var/www/ssl/private.key;
# Redirect @ to www
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name some-project.com;
rewrite ^ https://www.some-project.com$request_uri?;
}
# Redirect www HTTP to HTTPS
server {
listen 80;
server_name www.some-project.com;
rewrite ^ https://www.some-project.com$request_uri? permanent;
}
server {
listen 443 ssl;
server_name www.some-project.com;
include /etc/nginx/vhosts-includes/*.conf;
# Static Content
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /var/www/some-project/;
}
location / {
default_type "text/html";
alias /var/www/some-project/static/;
}
}
server {
listen 443 ssl;
server_name api.some-project.com;
# Reverse Proxy
location / {
proxy_pass http://localhost:5926;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
答案1
使用了“错误”的证书,因为 Nginx 需要完整的链 + 密钥。通过组合域和 CA 捆绑证书解决了这个问题。