📜

requestsの独自証明書エラーの解決法をCopilotに教えてもらった

2025/01/21に公開

!注意

こちらはCopilotの回答を基に情報をまとめたものであり、内容のすべてについて検証できているものではありません。誤った情報が含まれている可能性もゼロではないため、リンク先の参考情報も合わせて確認することをお勧めします。

エラー内容

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)

エラーの原因と解決方法

エラーの原因

このエラーは、SSL/TLS接続を確立する際に、ローカルの証明書ストアに信頼できる証明書が見つからない場合に発生します。具体的な原因としては以下が考えられます:

  • 証明書ファイルが存在しない、またはパスが間違っている
  • 証明書ファイルの形式が正しくない
  • システムの証明書ストアが更新されていない
  • プロキシサーバーの証明書が信頼されていない[1][2]

※Pythonのrequestsライブラリがデフォルトで参照するローカル証明書のパスは、システムに依存します。一般的には、requestsライブラリはcertifiパッケージを使用して、信頼できるCA証明書のバンドルを提供します。

デフォルトの証明書バンドルのパスは、以下のように確認できます:

import certifi
print(certifi.where())

このコードを実行すると、certifiが使用するCA証明書バンドルのパスが表示されます。通常、このパスはPythonの仮想環境やシステムのPythonインストールディレクトリ内にあります[3][4][5]

例えば、Windowsでは以下のようなパスが表示されることがあります:

C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python<バージョン>\lib\site-packages\certifi\cacert.pem

解決方法 ※ 3、6のみ検証済み

  1. 証明書ファイルを指定する:
    独自の証明書ファイルを使用する場合、PythonのSSLコンテキストにその証明書を追加します。

    import ssl
    import urllib.request
    
    url = "https://example.com"
    context = ssl.create_default_context()
    context.load_verify_locations(cafile="path/to/my_cert.pem")
    response = urllib.request.urlopen(url, context=context)
    print(response.read())
    
  2. requestsライブラリを使用する場合:
    requestsライブラリを使用している場合も、証明書ファイルを指定できます。

    import requests
    
    url = "https://example.com"
    response = requests.get(url, verify="path/to/my_cert.pem")
    print(response.text)
    
  3. 環境変数を設定する:
    REQUESTS_CA_BUNDLE環境変数を設定して、requestsライブラリが使用する証明書ファイルを指定します。

    set REQUESTS_CA_BUNDLE=path/to/my_cert.pem
    
  4. ファイル形式を変換する:
    証明書ファイルの形式が正しくない場合、OpenSSLを使用して変換します。

    openssl x509 -in path/to/certificate.crt -out path/to/certificate.pem -outform PEM
    
  5. システムに証明書をインストールする:
    システム全体に証明書をインストールすることで、すべてのアプリケーションがその証明書を使用できるようにします。

    # macOS
    sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain path/to/my_cert.pem
    
    # Linux
    sudo cp path/to/my_cert.pem /usr/local/share/ca-certificates/
    sudo update-ca-certificates
    
  6. certifiライブラリを更新する[6]:
    certifiライブラリが持つルート証明書のリストに独自の証明書を追加します。

    import certifi
    import requests
    
    # certifiの証明書バンドルに独自の証明書を追加
    with open(certifi.where(), 'a') as cert_file:
        cert_file.write(open("path/to/my_cert.pem").read())
    
    # requestsで使用
    url = "https://example.com"
    response = requests.get(url)
    print(response.text)
    

    参考: REQUESTS_CA_BUNDLEと証明書参照先

    requestsライブラリのデフォルト設定では、certifiパッケージが提供するCA証明書バンドルを使用します。具体的には、certificacert.pemファイルを参照します。REQUESTS_CA_BUNDLE環境変数を設定しない場合、requestsライブラリは自動的にcertifiの証明書バンドルを使用します[7][8]

    デフォルトの動作
    • デフォルトでは、certifiの証明書バンドルを使用:
    import requests
    import certifi
    
    print(certifi.where())  # certifiの証明書バンドルのパスを表示
    response = requests.get("https://example.com")
    print(response.text)
    
    REQUESTS_CA_BUNDLE環境変数の設定
    • REQUESTS_CA_BUNDLE環境変数を設定することで、カスタム証明書バンドルを使用:
    export REQUESTS_CA_BUNDLE=path/to/my_cert.pem
    

    この環境変数が設定されている場合、requestsライブラリはcertifiの証明書バンドルではなく、指定された証明書バンドルを使用します。設定されていない場合は、デフォルトでcertifiの証明書バンドルを使用します[8:1][9]

    まとめ
    • デフォルト値: certificacert.pemファイルを参照。
    • 環境変数が設定されている場合: REQUESTS_CA_BUNDLEで指定された証明書バンドルを使用。

    1: Advanced Usage — Requests Documentation
    2: How to Get Python Requests to Trust a Self-Signed SSL Certificate
    3: GitHub Issue on REQUESTS_CA_BUNDLE

注意点

  • パスの確認: 証明書ファイルのパスが正しいことを確認してください。
  • ファイルの存在確認: 指定したパスに証明書ファイルが存在するか確認してください。
  • バックアップ: 変更前に元のファイルのバックアップを取っておくことをお勧めします。
脚注
  1. https://qiita.com/ground0state/items/c4d7caa274b6e3d99e27 ↩︎

  2. https://rakuraku-engineer.com/posts/python-request-get-error-ssl/ ↩︎

  3. https://docs.python-requests.org/en/latest/api/?highlight=tls+authentication ↩︎

  4. https://pytutorial.com/python-requests-ssl-verification-a-complete-guide/ ↩︎

  5. https://www.pythonrequests.com/python-requests-verify-certificate-path/ ↩︎

  6. pemファイルに対し、独自証明書の中身を直接コピペすることでも対応可能 ↩︎

  7. https://github.com/psf/requests/issues/1491 ↩︎

  8. https://docs.python-requests.org/en/master/user/advanced.html ↩︎ ↩︎

  9. https://sqlpey.com/python/solved-how-to-get-python-requests-to-trust-a-self-signed-ssl-certificate/ ↩︎

Discussion