How to fix SSL: UNSUPPORTED_PROTOCOL EEROR in Python

0x00 前言

今天老大遇到了一个问题,说让我解决一下,结果配环境+搜了一下午也没给搞定。最后还是老大自己给解决了。WTCL。在此记录一下该问题

0x01 问题描述

操作系统环境

1
2
3
4
5
6
zeroyu@ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.1 LTS
Release: 20.04
Codename: focal

openssl为最新版且相关信息如下,从信息中可以看到是支持TLS1/TLS1.1的

1
2
3
4
5
6
7
zeroyu@ubuntu:~/Desktop$ openssl s_client -help 2>&1  > /dev/null | egrep "\-(ssl|tls)[^a-z]"
-ssl_config val Use specified configuration file
-tls1 Just use TLSv1
-tls1_1 Just use TLSv1.1
-tls1_2 Just use TLSv1.2
-tls1_3 Just use TLSv1.3
-ssl_client_engine val Specify engine to be used for client certificate operations

这套最新的环境在访问一些不支持TLS1.2的网站时候会出现一些问题,如果使用浏览器打开的话,浏览器会提示你启用对 TLS1.0/TLS1.1 的支持,此时只要点击了随后就完全OK。但是使用headless的话随后还会面对这个问题。比如使用如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from selenium import webdriver

try:
fireFoxOptions = webdriver.FirefoxOptions()
fireFoxOptions.set_headless()
brower = webdriver.Firefox(firefox_options=fireFoxOptions)

brower.get('https://IP')
print(brower.page_source)
finally:
try:
brower.close()
except:
pass

报错如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
zeroyu@ubuntu:~/Desktop$ python3 headless_ssl_error.py 
headless_ssl_error.py:5: DeprecationWarning: use setter for headless property instead of set_headless
fireFoxOptions.set_headless()
headless_ssl_error.py:7: DeprecationWarning: use options instead of firefox_options
brower = webdriver.Firefox(firefox_options=fireFoxOptions)
Traceback (most recent call last):
File "headless_ssl_error.py", line 9, in <module>
brower.get('https://IP')
File "/home/zeroyu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 333, in get
self.execute(Command.GET, {'url': url})
File "/home/zeroyu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/home/zeroyu/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: Reached error page: about:neterror?e=nssFailure2&u=https%3A//IP/&c=UTF-8&d=%20

如果使用Python的requests库的话,就会出现一下报错信息

1
2
3
4
5
6
7
8
9
10
11
zeroyu@ubuntu:~/Desktop$ python3 ssl_error.py 
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py", line 485, in wrap_socket
cnx.do_handshake()
File "/home/zeroyu/.local/lib/python3.8/site-packages/OpenSSL/SSL.py", line 1934, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "/home/zeroyu/.local/lib/python3.8/site-packages/OpenSSL/SSL.py", line 1671, in _raise_ssl_error
_raise_current_error()
File "/home/zeroyu/.local/lib/python3.8/site-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'ssl_choose_client_version', 'unsupported protocol')]

造成此问题的代码如下

1
2
3
4
5
6
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

req = requests.get("https://URL",verify=False)
print(req.status_code)

0x02 解决方案

思路无非就是启用对低版本TLS的支持,因为从openssl的相关信息中可以看到是对TLS1.0/TLS1.1 支持的。

但是Stack Overflow论坛上的众多帖子均不能够解决这个问题,最后老大给出的解决方案是

1
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS='DEFAULT:@SECLEVEL=1'

所以执行如下代码就完全没有问题了

1
2
3
4
5
6
7
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS='DEFAULT:@SECLEVEL=1'

req = requests.get("https://URL",verify=False)
print(req.status_code)

firefox headless对应的解决方案如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver

try:
fireFoxOptions = webdriver.FirefoxOptions()
fireFoxOptions.set_headless()
fireFoxOptions.set_preference('security.tls.version.enable-deprecated', True)
brower = webdriver.Firefox(firefox_options=fireFoxOptions)

brower.get('https://220.132.236.117')
print(brower.page_source)
finally:
try:
brower.close()
except:
pass

0x03 结语

如果还有更好的方案,欢迎评论 or 交流。