TL;DR — 素早い修正方法
PythonがサーバーのSSL証明書を検証できない原因は、その証明書に署名した認証局(CA)を信頼していないためです。状況に合った修正方法を選んでください:
- PythonをインストールしたばかりのmacOS:
/Applications/Python 3.x/Install Certificates.commandを実行する - 企業ネットワーク/自己署名証明書: PythonにカスタムCAバンドルを指定する
- pipが失敗する場合:
pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org <package>を使う - 応急処置(開発環境のみ): requestsに
verify=Falseを渡す — 本番環境では絶対に使用しない
このエラーの原因
PythonがHTTPS通信を行うたびにSSLハンドシェイクが発生します。Pythonはサーバーの証明書を信頼済みCA証明書バンドルと照合しますが、この確認に失敗するとこのエラーが発生します。
よくある原因:
- PythonにバンドルされているCAストアが古いか欠落している(python.orgからの新規macOSインストールではほぼ必ず発生する)
- ネットワークが企業プロキシ経由でトラフィックをルーティングしている — ZscalerやNetskopが最も一般的で、これらがHTTPS通信を独自の証明書で再署名する
- サーバーが自己署名証明書または内部発行の証明書を使用している
- システムのCAストアとPythonのCAストアが同期していない
certifiパッケージが見つからないか古くなっている
エラーの全文はこのような形式です:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)
修正1 — macOS:証明書インストーラーを実行する
macOS向けにpython.orgからダウンロードしたPythonには独自のSSLバンドルが付属していますが、そのバンドルはシステムのキーチェーンにリンクされておらず、自動更新もされません。Pythonに同梱されている証明書インストーラーを実行してください:
# 3.x を実際のバージョン(例:3.11、3.12)に置き換えてください
/Applications/Python\ 3.x/Install\ Certificates.command
または、ターミナルから同等のコマンドを実行します:
pip install --upgrade certifi
/usr/local/bin/python3 -c "import ssl; print(ssl.get_default_verify_paths())"
これにより certifi パッケージがインストールされ、PythonのSSLがそれにリンクされます。一度だけ実行すれば完了で、約10秒で終わります。
修正2 — certifiを更新またはインストールする
どのOSでも、certifi パッケージが古くなっていることがよくある原因です。まず更新してください:
pip install --upgrade certifi
次に、Pythonが実際にそれを使用していることを確認します:
python -c "import certifi; print(certifi.where())"
/usr/local/lib/python3.11/site-packages/certifi/cacert.pem のようなパスが表示されるはずです。requests ライブラリは自動的にcertifiを使用します — 両方のパッケージを常に最新の状態に保ってください。
修正3 — 企業ネットワーク/カスタムCA証明書
企業プロキシは最も見つけにくい原因です。ZscalerやNetskopなどのツールはHTTPS通信を傍受し、独自の証明書で再署名します。その証明書はデフォルトのCAバンドルに含まれていないため、Pythonは信頼しません。
手順1 — 会社のルートCA証明書を取得する。 IT部門に問い合わせるか、ブラウザの証明書ストアから .pem ファイルとしてエクスポートします。Chromeの場合:設定 → プライバシーとセキュリティ → セキュリティ → 証明書の管理 → ルートCAをエクスポート。
手順2 — certifiのCAバンドルに追記する:
import certifi
# certifiバンドルのパスを確認する
print(certifi.where()) # 例:/usr/local/lib/python3.11/site-packages/certifi/cacert.pem
# 会社の証明書をバンドルに追記する
cat /path/to/company-root-ca.pem >> $(python -c "import certifi; print(certifi.where())")
手順3 — 環境変数を設定する(より整理されており、certifiのアップグレード後も有効):
export REQUESTS_CA_BUNDLE=/path/to/company-root-ca.pem
export SSL_CERT_FILE=/path/to/company-root-ca.pem
これらの行を ~/.bashrc または ~/.zshrc に追加すると永続的に設定されます。
requestsを使用するコードの場合:
import requests
response = requests.get("https://internal.example.com", verify="/path/to/company-root-ca.pem")
print(response.status_code)
修正4 — pipがパッケージをインストールできない場合の修正
pipがパッケージをインストールする前に証明書エラーが発生することがあります。--trusted-host フラグを使って回避してください:
pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org requests
毎回フラグを入力するのは面倒です。pipの設定ファイルに永続的に保存しましょう:
# Linux/macOS: ~/.config/pip/pip.conf
# Windows: %APPDATA%\pip\pip.ini
[global]
trusted-host = pypi.org
files.pythonhosted.org
修正5 — SSL検証を無効にする(開発・デバッグ環境のみ)
これは根本的な修正ではなく、応急処置です。すべての証明書検証が無効になるため、ローカルデバッグのみに使用し、実際のデータを扱う本番コードには絶対に使用しないでください。
import requests
import urllib3
# InsecureRequestWarning を抑制する
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get("https://example.com", verify=False)
print(response.status_code)
urllib(標準ライブラリ)の場合:
import urllib.request
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with urllib.request.urlopen("https://example.com", context=ctx) as response:
print(response.read())
本当に — 前述のいずれかの修正方法を使ってください。verify=False は警告なしに中間者攻撃にさらされるリスクがあります。
修正6 — Windows:システム証明書ストアと同期する
WindowsはPythonとは別に独自の証明書ストアを管理しています。IT部門はグループポリシー経由で企業のCA証明書をそこに配布するのが一般的ですが、Pythonはデフォルトではそれを参照しません。
この問題を解決するために pip-system-certs をインストールしてください:
pip install pip-system-certs
インストール後、WindowsマシンがすでにTrustしている証明書はPythonも信頼するようになります。手動での証明書エクスポートは不要です。
修正の確認
修正を適用したら、簡単な動作確認を行ってください:
python -c "import requests; r = requests.get('https://httpbin.org/get'); print(r.status_code)"
期待される出力:200
エラーが発生していた特定のホストをテストする場合:
python -c "
import ssl, socket
ctx = ssl.create_default_context()
with ctx.wrap_socket(socket.socket(), server_hostname='your-target-host.com') as s:
s.connect(('your-target-host.com', 443))
print('Certificate OK:', s.getpeercert()['subject'])
"
正常に接続できれば、サーバーの証明書サブジェクト — (('commonName', 'your-target-host.com'),) のような形式 — が表示されます。ここでまだSSLCertVerificationErrorが発生する場合は、修正が適用されていません。
どの修正方法を使うべきか
- macOS + python.orgからのインストール → 修正1(Install Certificates.commandを実行)
- certifiが古い → 修正2(
pip install --upgrade certifi) - 企業プロキシ/内部CA → 修正3(会社のCAをバンドルに追加するか環境変数を設定)
- pipがPyPIに接続できない → 修正4(--trusted-hostフラグ)
- Windows + 企業証明書 → 修正6(pip-system-certs)
- ローカル開発のデバッグのみ → 修正5(verify=False)

