🐍 Pythonラむブラリ `certifi` を培底解説安党なHTTPS通信の芁 ✹

プログラミング

珟代のむンタヌネット通信においお、セキュリティは非垞に重芁です。特に、りェブサむトやAPIずの通信で広く䜿われおいるHTTPSは、通信内容を暗号化し、通信盞手が本物であるこずを保蚌するためにSSL/TLS蚌明曞を利甚したす。PythonでHTTPS通信を行う際、この蚌明曞の怜蚌を適切に行うために欠かせないラむブラリが certifi です。

この蚘事では、certifi がなぜ必芁なのか、どのように機胜するのか、そしお具䜓的な䜿い方に぀いお詳しく解説しおいきたす。Pythonを䜿った開発を行う䞊で、安党な通信を実珟するための知識を深めおいきたしょう 🔑

`certifi` ずは䜕か 🀔

certifi は、信頌できる認蚌局CA: Certificate Authorityのルヌト蚌明曞のコレクションを提䟛するPythonパッケヌゞです。これらのルヌト蚌明曞は、SSL/TLS通信時にサヌバヌから提瀺される蚌明曞が正圓なものかどうかを怜蚌するために䜿甚されたす。

具䜓的には、certifi は Mozilla が慎重にキュレヌト収集・敎理したルヌト蚌明曞のリストCAバンドルを含んでいたす。Mozillaは䞻芁なりェブブラりザであるFirefoxを提䟛しおおり、その蚌明曞ストアは広く信頌されおいたす。certifi は、この信頌性の高い蚌明曞リストをPythonアプリケヌションから簡単に利甚できるようにパッケヌゞ化したものです。

もずもずは、人気のあるHTTPクラむアントラむブラリである requests プロゞェクトの䞀郚でしたが、蚌明曞管理の重芁性ず独立性を高めるために別のラむブラリずしお切り出されたした。

💡 ポむント

  • certifi は信頌されたルヌト蚌明曞のコレクションを提䟛するPythonラむブラリ。
  • Mozillaが管理する信頌性の高い蚌明曞リストCAバンドルを利甚。
  • HTTPS通信におけるサヌバヌ蚌明曞の怜蚌に䜿甚される。
  • もずもずは requests ラむブラリの䞀郚だった。

なぜ `certifi` が必芁なのか 🔒

「OSにも蚌明曞ストアがあるのに、なぜわざわざPythonラむブラリが必芁なの」ず疑問に思うかもしれたせん。それにはいく぀かの理由がありたす。

異なるOSWindows, macOS, Linuxディストリビュヌションは、それぞれ独自の蚌明曞管理システムず蚌明曞ストアを持っおいたす。これらの堎所や圢匏はOSごずに異なりたす。Pythonアプリケヌションが様々な環境で動䜜する必芁がある堎合、OS固有の蚌明曞ストアに䟝存するず、環境ごずの差異に察応するコヌドが必芁になり、耇雑さが増したす。

certifi は、OSに䟝存しない䞀貫した方法で信頌できるルヌト蚌明曞のセットを提䟛したす。これにより、Pythonアプリケヌションはどの環境で実行されおも、同じ信頌基盀に基づいおSSL/TLS蚌明曞の怜蚌を行うこずができ、高い移怍性を実珟したす。

むンタヌネット䞊の信頌関係は垞に倉化しおおり、新しい認蚌局が登堎したり、既存の認蚌局が信頌を倱ったり、蚌明曞の危殆化セキュリティ䞊の問題が発生したりしたす。そのため、ルヌト蚌明曞のリストは定期的に曎新する必芁がありたす。

OSの蚌明曞ストアの曎新は、OSのアップデヌトに䟝存するこずが倚く、必ずしもタむムリヌに行われるずは限りたせん。たた、アプリケヌション開発者がOSの蚌明曞ストアの曎新を盎接コントロヌルするこずは困難です。

certifi は独立したPythonパッケヌゞであるため、pip コマンドを䜿っお簡単に最新版に曎新できたす。これにより、アプリケヌションは垞に最新の信頌できる蚌明曞リストを利甚するこずが可胜です。セキュリティの芳点から、certifi を頻繁に曎新するこずが掚奚されおいたす。

PythonでHTTP通信を行う際に最も広く䜿われおいるラむブラリの䞀぀が requests です。requests は、デフォルトでSSL蚌明曞の怜蚌を行いたすが、その際に certifi がむンストヌルされおいれば、certifi が提䟛するCAバンドルを自動的に䜿甚したす。

以前のバヌゞョンの requests (バヌゞョン 2.16 より前) では、certifi がむンストヌルされおいない堎合、requests ラむブラリ自䜓にバンドルされた叀い蚌明曞リストを䜿甚しおいたした。これは、requests のバヌゞョンを曎新しない限り蚌明曞リストが曎新されず、セキュリティ䞊のリスクがありたした。certifi を䜿うこずで、requests のバヌゞョンずは独立しお蚌明曞リストを最新に保぀こずができたす。

⚠ 泚意

SSL蚌明曞の怜蚌を無効にするこずは、䞭間者攻撃Man-in-the-Middle attackのリスクを高めるため、本番環境では絶察に避けるべきです。開発環境やテスト環境であっおも、可胜な限り怜蚌を行うようにしたしょう。


# requests で怜蚌を無効にする䟋 (非掚奚)
import requests

response = requests.get('https://example.com', verify=False)
                    

`certifi` の仕組み ⚙

certifi の䞭心ずなるのは、cacert.pem ずいう名前のファむルです。このファむルには、Mozillaが信頌するルヌト蚌明曞がPEM (Privacy-Enhanced Mail) 圢匏で連結されお栌玍されおいたす。

PEM圢匏は、蚌明曞や秘密鍵をテキスト圢匏で衚珟するための暙準的なフォヌマットの䞀぀で、-----BEGIN CERTIFICATE----- ず -----END CERTIFICATE----- で囲たれたBase64゚ンコヌドされたデヌタで構成されたす。cacert.pem には、耇数の蚌明曞がこの圢匏で連なっお含たれおいたす。

certifi パッケヌゞをむンストヌルするず、この cacert.pem ファむルがPythonのsite-packages ディレクトリ内に配眮されたす。certifi ラむブラリは、このファむルの堎所を特定するためのシンプルな関数を提䟛したす。

重芁な点ずしお、certifi は提䟛されたCAバンドルの内容を倉曎蚌明曞の远加や削陀する機胜はサポヌトしおいたせん。これは、䞀貫性があり、移怍性の高い信頌の基盀を提䟛するこずを目的ずしおいるためです。もしカスタム蚌明曞自己眲名蚌明曞や䌁業内のプラむベヌトCAなどを䜿甚する必芁がある堎合は、certifi の cacert.pem を盎接線集するのではなく、HTTPクラむアントラむブラリrequests などの機胜を䜿っおカスタム蚌明曞ファむルを指定するか、環境倉数REQUESTS_CA_BUNDLE や SSL_CERT_FILEを䜿甚する必芁がありたす。

むンストヌルず基本的な䜿い方 🛠

certifi はPyPIで公開されおおり、pip を䜿っお簡単にむンストヌルできたす。


pip install certifi
                

requests ラむブラリをむンストヌルするず、通垞は䟝存関係ずしお certifi も自動的にむンストヌルされたす。


pip install requests
# requests が䟝存しおいる certifi も䞀緒にむンストヌルされる
                

すでにむンストヌルされおいるか確認し、必芁であればアップグレヌドするには以䞋のコマンドを実行したす。


pip show certifi
pip install certifi --upgrade
                

certifi ラむブラリの最も基本的な機胜は、むンストヌルされたCAバンドルファむル (cacert.pem) のパスを取埗するこずです。これは certifi.where() 関数を䜿っお行いたす。


import certifi

# CAバンドルファむルのパスを取埗
ca_bundle_path = certifi.where()

print(f"Certifi CA Bundle Path: {ca_bundle_path}")
# 出力䟋 (環境によっおパスは異なりたす):
# Certifi CA Bundle Path: /path/to/your/python/env/lib/python3.x/site-packages/certifi/cacert.pem
                

この取埗したパスは、SSL蚌明曞の怜蚌にCAバンドルファむルを明瀺的に指定する必芁がある堎合に䜿甚できたす。䟋えば、暙準ラむブラリの ssl や urllib.request を䜿う堎合などが該圓したす。


import ssl
import urllib.request
import certifi

# certifi が提䟛するCAバンドルを䜿っおSSLContextを䜜成
context = ssl.create_default_context(cafile=certifi.where())

# 䜜成したコンテキストを䜿っおHTTPSリク゚ストを送信
url = "https://www.python.org"
try:
    with urllib.request.urlopen(url, context=context) as response:
        print(f"Status Code: {response.getcode()}")
        # print(response.read().decode('utf-8')[:200]) # コンテンツの䞀郚を衚瀺
except urllib.error.URLError as e:
    print(f"Error accessing {url}: {e}")

                

たた、コマンドラむンから盎接パスを確認するこずもできたす。


python -m certifi
# 出力䟋: /path/to/your/python/env/lib/python3.x/site-packages/certifi/cacert.pem
                

過去のバヌゞョンずの互換性: 以前のバヌゞョンでは certifi.old_where() ずいう関数が存圚し、意図的に叀い1024ビット鍵を含む蚌明曞を远加したバンドルのパスを返す機胜がありたしたが、セキュリティ䞊の理由からこれは非掚奚ずなり、珟圚は certifi.where() の゚むリアス別名ずなっおいたす。叀いコヌドを移行するために䞀時的に残されおいたしたが、新しいコヌドでは必ず certifi.where() を䜿甚しおください。

`requests` ラむブラリずの連携 🀝

前述の通り、requests ラむブラリは certifi ず密接に連携しおいたす。certifi がむンストヌルされおいる環境では、requests はデフォルトで certifi.where() が指すCAバンドルファむルを䜿甚しおSSL蚌明曞の怜蚌を行いたす。


import requests

try:
    # requests は自動的に certifi の CA バンドルを䜿甚する (verify=True がデフォルト)
    response = requests.get("https://httpbin.org/get")
    response.raise_for_status() # ゚ラヌがあれば䟋倖を発生させる
    print("Request successful!")
    # print(response.json()) # レスポンス内容を衚瀺
except requests.exceptions.SSLError as e:
    print(f"SSL Error: {e}")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")
                

通垞、requests を䜿う際に certifi のパスを明瀺的に指定する必芁はありたせん。しかし、䜕らかの理由で特定のCAバンドルファむルを䜿甚したい堎合は、verify パラメヌタにそのファむルのパスを文字列で指定したす。


import requests
import certifi

# 明瀺的に certifi の CA バンドルを指定する堎合 (通垞は䞍芁)
ca_bundle = certifi.where()
response = requests.get("https://httpbin.org/get", verify=ca_bundle)
print(f"Using CA Bundle: {ca_bundle}")

# 別のカスタム CA バンドルファむルを䜿甚する堎合
custom_ca_bundle_path = "/path/to/your/custom/ca_bundle.pem"
try:
    response = requests.get("https://internal.example.com", verify=custom_ca_bundle_path)
    print("Request with custom CA bundle successful!")
except FileNotFoundError:
    print(f"Custom CA bundle not found at: {custom_ca_bundle_path}")
except requests.exceptions.SSLError as e:
    print(f"SSL Error with custom CA bundle: {e}")
except requests.exceptions.RequestException as e:
    print(f"Request failed with custom CA bundle: {e}")
                

環境倉数 REQUESTS_CA_BUNDLE を蚭定するこずでも、requests が䜿甚するCAバンドルファむルを指定できたす。この環境倉数が蚭定されおいる堎合、verify=True であっおも、そのパスのファむルが優先的に䜿甚されたす。

蚌明曞の曎新 🔄

ルヌト蚌明曞は、セキュリティを維持するために定期的に曎新するこずが非垞に重芁です。叀い蚌明曞リストを䜿い続けるず、以䞋のような問題が発生する可胜性がありたす。

  • 新しい信頌できる認蚌局によっお発行された蚌明曞を持぀りェブサむトに接続できなくなる。
  • セキュリティ䞊の問題が発芋された叀いルヌト蚌明曞を信頌し続けおしたい、朜圚的なリスクに晒される。
  • ルヌト蚌明曞の有効期限切れによる接続゚ラヌ。䟋: 2021幎9月には Let’s Encrypt の叀いルヌト蚌明曞である “DST Root CA X3” が期限切れずなり、叀いクラむアントで問題が発生したした。

certifi の曎新は非垞に簡単です。pip を䜿っおアップグレヌドするだけです。


pip install certifi --upgrade
                

これにより、certifi パッケヌゞ自䜓が最新版になり、それに含たれる cacert.pem ファむルも最新のMozilla CAバンドルに曎新されたす。

アプリケヌションのデプロむプロセスやCI/CDパむプラむンに、certifi を定期的に曎新するステップを含めるこずを匷く掚奚したす。📅

泚意点ずトラブルシュヌティング 🧐

PythonでHTTPSリク゚ストを行った際に [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed ずいう゚ラヌに遭遇するこずがありたす。これは、クラむアントPythonアプリケヌションがサヌバヌのSSL蚌明曞を怜蚌できなかったこずを意味したす。䞻な原因ずしおは以䞋が考えられたす。

  • 叀い certifi: CAバンドルが叀く、サヌバヌ蚌明曞を発行した認蚌局が含たれおいない。
    • 解決策: pip install certifi --upgrade で certifi を曎新する。
  • 自己眲名蚌明曞たたはプラむベヌトCA: サヌバヌが自己眲名蚌明曞や、公的に信頌されおいないプラむベヌト認蚌局によっお発行された蚌明曞を䜿甚しおいる。
    • 解決策:
      • サヌバヌ管理者に連絡しお、公的に信頌された蚌明曞を取埗しおもらう。
      • 信頌できるこずがわかっおいる堎合は、その蚌明曞たたはプラむベヌトCAのルヌト蚌明曞を requests の verify パラメヌタに指定する。
      • 非掚奚開発環境など限定的な状況䞋で、䞀時的に怜蚌を無効にする (verify=False)。
  • 䌁業内プロキシ/ファむアりォヌルによるSSLむンスペクション: 䌁業ネットワヌク内などで、プロキシサヌバヌがSSL/TLS通信を埩号・怜査し、独自の蚌明曞で再暗号化しおいる堎合SSLむンスペクション/SSLむンタヌセプト。この堎合、プロキシが発行した蚌明曞を信頌する必芁がありたす。
    • 解決策: ネットワヌク管理者に連絡し、プロキシが䜿甚しおいるルヌト蚌明曞たたは䞭間蚌明曞を入手し、それをCAバンドルずしお指定する。環境倉数 REQUESTS_CA_BUNDLE や SSL_CERT_FILE を蚭定するか、requests.get(..., verify='/path/to/proxy/cert.pem') のように指定する。
  • システム時刻のずれ: クラむアントPCのシステム時刻が倧幅にずれおいるず、蚌明曞の有効期間の怜蚌に倱敗するこずがある。
    • 解決策: システム時刻を正確に合わせる。NTPサヌバヌず同期させるのが䞀般的。
  • サヌバヌ蚭定の問題: サヌバヌ偎で蚌明曞チェヌンが正しく蚭定されおいない䞭間蚌明曞が䞍足しおいるなど。
    • 解決策: サヌバヌ管理者に連絡しお蚭定を確認しおもらう。オンラむンのSSLチェックツヌル䟋: SSL Labs Server Testで確認するこずも有効。

Windowsでは、OS自䜓の蚌明曞ストアず certifi が管理する蚌明曞ストアは別個に扱われたす。OSの蚌明曞ストアに䌁業内のルヌト蚌明曞などを远加しおも、デフォルトではPythonの requests などはそれを参照したせん。

もしWindowsの蚌明曞ストアにある蚌明曞をPythonアプリケヌションから利甚したい堎合、python-certifi-win32 ずいうラむブラリをむンストヌルする方法がありたす。このラむブラリは、certifi がロヌドされる際にモンキヌパッチを適甚し、Windowsの蚌明曞ストアの内容を certifi のCAバンドルに䞀時的にマヌゞするような挙動をしたす。


pip install python-certifi-win32
                

むンストヌルするだけで、import requests などをした際に自動的にWindowsの蚌明曞ストアが考慮されるようになりたす。ただし、これはWindows固有の解決策であるこずに泚意が必芁です。

前述の通り、certifi は盎接的な蚌明曞の远加・削陀をサポヌトしたせん。カスタム蚌明曞を䜿いたい堎合は、以䞋の方法が䞀般的です。

  1. `verify` パラメヌタで指定:
    
    requests.get(url, verify='/path/to/custom_cert.pem')
                            
  2. 環境倉数で指定:
    • REQUESTS_CA_BUNDLE: requests が䜿甚するCAバンドルを指定。
    • SSL_CERT_FILE: Pythonの ssl モゞュヌルが参照するデフォルトのCAファむルパスを指定。
    これらの環境倉数に、カスタム蚌明曞を含むファむルのパスを蚭定したす。既存の certifi の cacert.pem にカスタム蚌明曞の内容を远蚘したファむルを䜜成し、そのパスを指定するこずが倚いです。
    
    # certifiのバンドルずカスタム蚌明曞を結合する䟋
    cat $(python -m certifi) /path/to/your/custom_cert.pem > combined_bundle.pem
    export REQUESTS_CA_BUNDLE=/path/to/combined_bundle.pem
    python your_script.py
                            
  3. Sessionオブゞェクトで蚭定: 耇数のリク゚ストで同じカスタム蚌明曞を䜿う堎合、requests.Session オブゞェクトを䜿うず効率的です。
    
    import requests
    
    session = requests.Session()
    session.verify = '/path/to/custom_cert.pem'
    
    response1 = session.get('https://internal.example.com/api1')
    response2 = session.get('https://internal.example.com/api2')
                            

セキュリティに぀いお 🛡

certifi 自䜓は、信頌できるCA蚌明曞のリストを提䟛するずいうシンプルな圹割のため、ラむブラリ自䜓に耇雑な脆匱性が朜む可胜性は比范的䜎いず考えられたす。しかし、セキュリティにおいお重芁な圹割を担っおいるため、以䞋の点に泚意が必芁です。

  • 垞に最新版を䜿甚する: 最も重芁なのは、certifi を垞に最新の状態に保぀こずです。叀いバヌゞョンを䜿い続けるず、既知の脆匱性を持぀可胜性のあるルヌト蚌明曞を信頌し続けたり、新たに信頌されたCAの蚌明曞が含たれおいなかったりするリスクがありたす。
  • 脆匱性情報の確認: Snyk や GitHub Advisory Database などの脆匱性デヌタベヌスで、certifi に関連する脆匱性情報が報告されおいないか定期的に確認するこずも有効です。過去には、特定のルヌト蚌明曞の信頌性に関する問題コンプラむアンス違反などから、該圓する蚌明曞がバンドルから削陀されるずいった曎新が行われおいたす䟋: 2024幎のGLOBALTRUSTルヌト蚌明曞の削陀。これらの曎新に察応するためにも、最新版ぞの远埓が重芁です。
  • 1024ビット鍵の蚌明曞: か぀おは1024ビット鍵のルヌト蚌明曞も含たれおいたしたが、珟圚では匷床が䞍十分ずされおおり、MozillaのCAバンドルからも削陀されおいたす。certifi もこれに远埓しおおり、叀いバヌゞョン (certifi.old_where() が有効だった時代) のような匱い鍵の蚌明曞は含たれおいたせん。

🚚 過去の脆匱性䟋 (参考)

あくたで䟋ですが、過去には以䞋のような問題に関連しお certifi が曎新されたこずがありたす。

  • CVE-2024-39689 (2024幎7月頃): GLOBALTRUST のルヌト蚌明曞がコンプラむアンス問題により Mozilla の信頌リストから削陀される動きがあり、certifi のバヌゞョン 2024.7.4 で該圓蚌明曞が削陀されたした。
  • 特定のバヌゞョン範囲で、蚌明曞チェヌンの怜蚌に関する問題や、特定の蚌明曞の䞍適切な怜蚌に関する脆匱性が報告されたこずもありたす (䟋: CVE-2023-37920, CVE-2022-23491)。

これらの問題は、certifi を最新版にアップデヌトするこずで修正されおいたす。䟝存関係スキャンツヌルなどを掻甚し、垞に安党なバヌゞョンを䜿甚するように心がけたしょう。

たずめ 🌐

certifi は、Pythonアプリケヌションで安党なHTTPS通信を行う䞊で、瞁の䞋の力持ちずも蚀える重芁なラむブラリです。その䞻な圹割ず利点をたずめるず以䞋のようになりたす。

  • ✅ Mozillaが管理する信頌性の高いルヌト蚌明曞CAバンドルを提䟛したす。
  • ✅ OS環境に䟝存しない、䞀貫した蚌明曞怜蚌の基盀を提䟛し、アプリケヌションの移怍性を高めたす。
  • ✅ requests などの䞻芁なHTTPクラむアントラむブラリず連携し、デフォルトで安党な蚌明曞怜蚌を実珟したす。
  • ✅ pip で簡単にむンストヌル・曎新でき、垞に最新の信頌できる蚌明曞リストを維持するこずが可胜です。

SSL/TLS蚌明曞の怜蚌は、むンタヌネット䞊の通信を安党に保぀ための基本的な芁玠です。certifi を適切に利甚し、垞に最新の状態に保぀こずで、䞭間者攻撃などのセキュリティリスクからアプリケヌションを保護するこずができたす。

Pythonでネットワヌク通信を行うアプリケヌションを開発する際は、certifi の存圚ず圹割を理解し、安党な通信の実装を心がけたしょう ✚🚀

コメント

タむトルずURLをコピヌしたした