Python

urllib and "SSL: CERTIFICATE_VERIFY_FAILED" Error の原因と直し方【Dockerで検証済み】

Python

urllib and "SSL: CERTIFICATE_VERIFY_FAILED" Error の原因と解決方法。検証済みの解決コマンド付きで、現象→原因→解決→確認の順に最短で直せます。

このエラーが出ていませんか

エラー出力
urllib and "SSL: CERTIFICATE_VERIFY_FAILED" Error

結論

結論:まずこれで直ります

Python の urllib(内部で ssl モジュールを使用)は HTTPS 接続時にサーバー証明書をシステムの CA バンドルで検証します。下の解決コマンドを順に実行すれば直ります。

解決コマンド
pip install --upgrade certifi
python3 -c "
import ssl
import certifi
import urllib.request

# certifi が提供する最新の CA バンドルを明示的に指定して SSLContext を構築する
ctx = ssl.create_default_context(cafile=certifi.where())
urllib.request.urlopen('https://www.python.org/', context=ctx)
print('OK: SSL verification succeeded with certifi CA bundle')
"

どんなエラーか

次の操作を行うと(検証環境: python:3.11)、上記のエラーが発生します。まずは下の再現コマンドで、同じ状況を再現できることを確認してください。

検証環境:python:3.11

再現コマンド
python3 -c "
import ssl
import urllib.request

# 空の SSLContext(CA バンドルを一切ロードしない)を使って HTTPS リクエストを送る
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = True
ctx.verify_mode = ssl.CERT_REQUIRED
# CA をロードしないため certificate verify failed が発生する
urllib.request.urlopen('https://www.python.org/', context=ctx)
"

なぜ起きるのか

Python の urllib(内部で ssl モジュールを使用)は HTTPS 接続時にサーバー証明書をシステムの CA バンドルで検証します。CA バンドルが存在しない・古い・パスが正しく設定されていない場合、OpenSSL が証明書チェーンを検証できず『SSL: CERTIFICATE_VERIFY_FAILED』を送出します。特に macOS の Python.org 公式インストーラー版や、最小構成の Linux コンテナでよく発生します。根本的な修正は、信頼できる CA 証明書集合を正しく提供することです。最も確実な方法は `pip install --upgrade certifi` で最新の Mozilla CA バンドルを取得し、`ssl.create_default_context(cafile=certifi.where())` のようにそのパスを SSLContext に渡すことです。こうすることで urllib は正しい CA チェーンを参照でき、証明書検証が成功します。`verify=False` や `--trusted-host` のような検証無効化は証明書の真正性チェックを完全に捨てる行為であり、中間者攻撃のリスクを生むため解決策として採用してはなりません。

解決手順

修正コマンド
pip install --upgrade certifi
python3 -c "
import ssl
import certifi
import urllib.request

# certifi が提供する最新の CA バンドルを明示的に指定して SSLContext を構築する
ctx = ssl.create_default_context(cafile=certifi.where())
urllib.request.urlopen('https://www.python.org/', context=ctx)
print('OK: SSL verification succeeded with certifi CA bundle')
"

直ったか確認する

確認コマンド
python3 -c "
import ssl, certifi, urllib.request
ctx = ssl.create_default_context(cafile=certifi.where())
resp = urllib.request.urlopen('https://www.python.org/', context=ctx)
assert resp.status == 200, f'unexpected status: {resp.status}'
print('verify OK')
"

動画で見る

この手順でも直らない場合は。

エラー文をそのまま貼り付けて送っていただければ、原因の当たりをつけてお返しします。 ヒアリングは無料です。業務システムの内製化・保守のご相談も受け付けています。

無料相談を申し込む

Related

無料相談(ヒアリング0円)
無料相談0 YEN