🐳

SSL: WRONG_SIGNATURE_TYPE エラーの解消方法

2023/08/25に公開

はじめに

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 になります。

main.py
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))

Dockerfile
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 に以下の設定を追加する方法が紹介されていました。

/etc/ssl/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 以下に固定することで、利用可能であることは分かりました。とはいえ、古いバージョンはサポートが終了してしまうので、定期的にバージョンアップを検討しなければなりません。色々と調査して見つけた方法を試してみました。
https://stackoverflow.com/questions/61631955/python-requests-ssl-error-during-requests

main.py
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