PythonのHTTPSリクエストでssl.SSLCertVerificationError: certificate verify failedを修正する

beginner🐍 Python2026-03-20| Python 3.6以降、macOS / Linux / Windows、requestsライブラリまたはurllib

Error Message

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)
#python#ssl#requests#https#証明書

TL;DR

PythonがサーバーのSSL証明書を信頼済みCAバンドルと照合できない状態です。状況に合った修正方法を選んでください:

  • macOS:Pythonに同梱されている Install Certificates.command スクリプトを実行する。
  • requests を使用している場合(OS問わず)certifi をアップグレードすれば、ほぼ解決できる。
  • 企業証明書/自己署名証明書:CA証明書をトラストストアに追加する。

verify=False による手抜き対処は避けてください。SSLの保護をすべて無効化してしまい、本番環境での中間者攻撃にさらされるリスクがあります。

エラーが発生する原因

PythonがHTTPSリクエストを行うたびに、証明書の検証が実行されます。Pythonはサーバーの証明書を、信頼済み認証局(CA)のバンドルと照合します。この検証が失敗する一般的な原因は以下のとおりです:

  • PythonのCAバンドルが存在しないか古い — macOSのクリーンインストール直後によく発生する。
  • サーバーが自己署名証明書または企業内のプライベートCAを使用している。
  • 企業のプロキシ(Zscaler、Charles、Fiddlerなど)がSSLインスペクションを行い、独自の証明書を提示している。
  • Pythonの ssl モジュールがシステムのCAストアにアクセスできない。

完全なトレースバックは次のようになります:

requests.exceptions.SSLError: HTTPSConnectionPool(host='example.com', port=443): Max retries exceeded with url: /
Caused by: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)

修正方法1 — macOS:証明書インストーラーを実行する

macOSにPythonをクリーンインストールした場合、システムのキーチェーンを完全にスキップします。インストーラーにはこの問題に対応する一度きりの修正スクリプトが同梱されています。

ターミナルを開き、以下を実行します:

/Applications/Python\ 3.x/Install\ Certificates.command

3.x は実際のバージョン(例:3.12)に置き換えてください。pyenv や Homebrew を使用している場合は、代わりに以下を実行します:

pip install --upgrade certifi

Pythonが有効なバンドルを見つけられているか確認します:

python -c "import ssl; print(ssl.get_default_verify_paths())"

ディスク上の実際のファイルを指す、空でない cafile または capath が表示されれば問題ありません。

修正方法2 — certifi をインストールまたはアップグレードする

certifirequests が依存するキュレーション済みのCAバンドルを提供します。古くなっているか存在しない場合、証明書検証が失敗します。

pip install --upgrade certifi

仮想環境(virtualenv)を使用している場合は、先にアクティベートしてください。そうしないと、誤った環境をアップグレードしてしまいます:

source venv/bin/activate
pip install --upgrade certifi

Pythonが実際に使用するバンドルを確認します:

python -c "import certifi; print(certifi.where())"

次に簡単な動作確認テストを実行します:

import requests
r = requests.get('https://example.com')
print(r.status_code)  # 200 が表示されれば成功

修正方法3 — カスタム証明書または企業のCA証明書を追加する

企業のファイアウォール内にいる場合、ZscalerやCharles Proxy、または社内PKIなどのツールがすべてのHTTPS接続に独自のCAを挿入します。PythonはそのCAを認識しないため、エラーが発生します。

ITチームからCA証明書(通常は .crt または .pem ファイル)を入手し、以下のいずれかの方法を選択してください:

オプションA:requests に証明書パスを直接渡す

import requests

r = requests.get('https://internal.company.com', verify='/path/to/company-ca.crt')
print(r.status_code)

オプションB:環境変数を設定する

REQUESTS_CA_BUNDLE または SSL_CERT_FILE を参照するすべてのライブラリに有効です。再起動後も設定が保持されるよう、シェルプロファイルに追加してください。

# Linux / macOS — ~/.bashrc または ~/.zshrc に追加
export REQUESTS_CA_BUNDLE=/path/to/company-ca.crt
export SSL_CERT_FILE=/path/to/company-ca.crt
# Windows (PowerShell)
$env:REQUESTS_CA_BUNDLE = "C:\certs\company-ca.crt"

オプションC:certifi のバンドルに証明書を追記する

環境内のすべてのスクリプトに対してグローバルな修正が必要な場合に有効です:

import certifi

# 環境セットアップ時に一度だけ実行する
with open('/path/to/company-ca.crt', 'r') as f:
    custom_cert = f.read()

certifi_bundle = certifi.where()
with open(certifi_bundle, 'a') as bundle:
    bundle.write('\n' + custom_cert)

注意:後で certifi をアップグレードすると、この変更は上書きされます。アップグレード後にスクリプトを再実行してください。

修正方法4 — urllib または http.client(requests を使わない場合)

requests を使用していない場合、標準ライブラリでは手動でSSLコンテキストを設定する必要があります:

import urllib.request
import ssl
import certifi

# certifi のバンドルを使用したコンテキストを構築する
ctx = ssl.create_default_context(cafile=certifi.where())

with urllib.request.urlopen('https://example.com', context=ctx) as response:
    print(response.read())

やってはいけないこと

Stack Overflow には証明書検証を無効化することを勧める回答が多数ありますが、絶対に使用しないでください:

# 本番環境では絶対に使用しないこと
import requests
requests.get('https://example.com', verify=False)  # 安全ではない

# これも危険
import ssl
ssl._create_default_https_context = ssl._create_unverified_context  # 安全ではない

どちらの方法もエラーを消しますが、それは検証を完全にオフにすることで行っています。接続を傍受した攻撃者が偽の証明書を提示しても、Pythonは警告を出しません。データが漏洩します。

許容できる唯一のケースは、実際のデータを扱わない localhost 向けの使い捨てテストスクリプトのみです。外部サーバーに対しては絶対に使用しないでください。

修正が成功したか確認する

以下のスニペットを実行して、すべてが正しく設定されているか確認します:

python - <<'EOF'
import requests
import ssl
import certifi

print('certifi bundle:', certifi.where())
print('ssl default paths:', ssl.get_default_verify_paths())

r = requests.get('https://httpbin.org/get')
print('HTTP status:', r.status_code)  # 200 が期待値
EOF

certifi をアップグレードしても失敗する場合、仮想環境が古いバージョンを参照している可能性があります。以下で確認してください:

pip show certifi

Location フィールドはアクティブな仮想環境内を指している必要があります。/usr/lib/python3 のようなシステムのPythonパスではいけません。

どの修正方法を使うべきか:簡単な判断ガイド

  • macOS、Pythonクリーンインストール → 修正方法1(Install Certificates.command を実行)
  • OS問わず、証明書が古い → 修正方法2(certifi をアップグレード)
  • 企業ネットワーク/SSLインスペクション → 修正方法3(企業のCAを追加)
  • requests を使用していない → 修正方法4(certifi コンテキストで urllib を使用)

Related Error Notes