SSL: WRONG_SIGNATURE_TYPE エラーの解消方法
はじめに
Docker の Python イメージで動かしている ウェブサイトに HTTP リクエストするプログラム
を久しぶりに Docker ビルドしたところ、一部のウェブサイトへのリクエストで SSL エラーとなりました。
HTTPSConnectionPool(host='xxx.co.jp', port=443): Max retries exceeded with url: /xxx/xxx.html (Caused by SSLError(SSLError(1, '[SSL: WRONG_SIGNATURE_TYPE] wrong signature type (_ssl.c:1002)')))
今回は、SSL: WRONG_SIGNATURE_TYPE エラーの解消方法を共有したいと思います。
エラーになったコード
エラーになった Python コードと Dockerfile を示します。実行環境は、Docker Desktop for Mac with Intel chip になります。
import requests
import chardet
url = 'https://xxx.co.jp/xxx/xxx.html'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0'}
res = requests.get(url,
allow_redirects=False,
verify=False,
headers=headers,
timeout=15)
if res.status_code == '200':
content = res.content
encoding = chardet.detect(content)['encoding']
print(content.decode(encoding))
FROM python:3
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD [ "python3", "./main.py" ]
OpenSSL設定変更
WRONG_SIGNATURE_TYPE エラーについて調べてみると、アクセスしようとしているサーバーのセキュリティレベルが低い場合にこのエラーが出ることがあるようです。クライアント側の対策として、openssl.cnf に以下の設定を追加する方法が紹介されていました。
openssl_conf = default_conf
[ default_conf ]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT:@SECLEVEL=1
試してみましたが、残念ながら私の環境では効果がありませんでした。
Python バージョンのダウングレード
次に、以前は同じソースコードで問題なかったことから、Python バージョンのダウングレードを試したところ、結果は以下になりました。
結果 | Python バージョン |
---|---|
OK | 3.7.1 ~ 3.7.16, 3.8.1 ~ 3.8.16, 3.9.1 ~ 3.9.16 |
NG | 3.7.17, 3.8.17, 3.9.17, 3.10.1 ~ 3.10.12, 3.11.1 ~ 3.11.4 |
Python 3.11、3.10 ではエラーになりました。3.7、3.8、3.9 については最終バージョンのみエラーになり、それ以外のバージョンではリクエストは成功することが分かりました。
Python コード修正
ソースコードの修正をしなくても Python のバージョンを 3.9 以下に固定することで、利用可能であることは分かりました。とはいえ、古いバージョンはサポートが終了してしまうので、定期的にバージョンアップを検討しなければなりません。色々と調査して見つけた方法を試してみました。
import requests
import chardet
import ssl
from urllib3 import poolmanager
class TLSAdapter(requests.adapters.HTTPAdapter):
def init_poolmanager(self, connections, maxsize, block=False):
ctx = ssl.create_default_context()
ctx.set_ciphers('DEFAULT@SECLEVEL=1')
self.poolmanager = poolmanager.PoolManager(
num_pools=connections,
maxsize=maxsize,
block=block,
ssl_version=ssl.PROTOCOL_TLS,
ssl_context=ctx)
url = "https://xxx.co.jp/xxx/xxx.html"
session = requests.session()
session.mount('https://', TLSAdapter())
res = session.get(url)
if res.status_code == '200':
content = res.content
encoding = chardet.detect(content)['encoding']
print(content.decode(encoding))
PoolManager の初期化時にデフォルトセキュリティレベルを設定しています。
Python 3.10 と 3.11 の各バージョンでの動作確認の結果を示します。こちらも最終バージョンではエラーになりますが、それ以外のバージョンでは成功しました。
結果 | Python バージョン |
---|---|
OK | 3.10.1 ~ 3.10.11, 3.11.1 ~ 3.11.3 |
NG | 3.10.12, 3.11.4 |
おわりに
今回は、HTTP リクエストでの SSL: WRONG_SIGNATURE_TYPE エラーの解消方法を共有しました。環境やリクエスト先のセキュリティ設定などで状況が変わると思いますので、Python バージョンを色々と変えて試してみる必要がありそうです。Docker を使えば簡単に動作確認できるので、改めて便利だなと思いました。
Discussion