はじめに
目的
本ドキュメントは「ssl certificate_verify_failed」エラーについて、検索結果をもとに体系的に整理したものです。エラーの意味、発生原因、対処方法を分かりやすくまとめ、技術ブログとして転用できる形で提供します。
背景
このエラーは特にPythonでHTTPS通信を行う際に見かけます。たとえばrequestsやurllibで外部APIに接続したときに「証明書が検証できない」といったメッセージが出ることがあります。原因は複数あり、環境依存の問題や設定ミスが多く見られます。
対象読者
開発者や運用担当者、学習中のエンジニアを想定しています。初歩的なネットワーク用語やPythonの基本は知っている前提ですが、専門用語は最小限に留めて具体例で補足します。
本書の構成と使い方
第2章でエラーの意味を明確にし、第3章で主な原因を列挙します。第4章では実際に使える切り分け手順を紹介します。順を追って確認することで、問題解決に役立ててください。
SSL「certificate_verify_failed」とは何か
概要
「SSL: CERTIFICATE_VERIFY_FAILED」は、クライアントがサーバーのSSL/TLS証明書を検証できなかったときに出るエラーです。HTTPS接続の初期段階で行われるTLSハンドシェイク中に発生します。表面上は「証明書が信用できない」という意味です。
何を検証しているか
クライアントは次の点を確認します。
– 証明書が信頼できる認証局(CA)により発行されているか
– 接続先のドメイン名と証明書の名前が一致しているか
– 証明書の有効期限内か
– サーバーが必要な中間証明書を含んだ完全なチェーンを返しているか
よく見かける場面と例
- Pythonのrequestsや各種SDKでHTTPS呼び出ししたとき
- Dockerコンテナ内でホストのCAが利用できないとき
- Webhookやクラウドサービス間の通信で証明書チェーンが不完全なとき
- 社内プロキシやウイルス対策ソフトが通信を中継・検査している環境
簡単な例
ブラウザでは警告が出ますが、プログラム側では例外(certificate_verify_failed)になり処理が止まります。開発中に自己署名証明書を使っている場合や中間証明書を設定し忘れている場合に多く発生します。
次章では、具体的な原因を詳しく見ていきます。
certificate_verify_failed が発生する主な原因
1) ルートCA証明書が不足・古い
システムやコンテナのCAストアに最新のルート証明書が入っていないと検証に失敗します。例えば古いDockerイメージや初期状態のサーバーで起きやすいです。対処はOSやCAバンドルの更新です。
2) 自己署名証明書・社内CAの未登録
社内の独自CAや開発用の自己署名証明書を信頼リストに登録していないと拒否されます。開発環境では社内CAを明示的に追加してください。
3) 証明書チェーンの不完全・順序不正
中間証明書が欠けている、あるいは順序が間違っているとブラウザやクライアントがチェーンを組めません。サーバー設定で完全なチェーンを返すか、証明書ファイルを確認します。
4) ドメイン不一致・有効期限の問題
証明書のコモンネームやSANにアクセス先のドメインが含まれていない、期限切れ、または有効化前の証明書は検証に失敗します。対象ドメインと期間を確認してください。
5) 証明書の失効
OCSPやCRLで失効が確認されると拒否されます。失効情報の確認やOCSPレスポンダーの到達性をチェックします。
6) プロキシ・ファイアウォール・ウイルス対策によるSSLインターセプト
企業やセキュリティソフトが通信を中継して独自証明書を差し込むことがあります。この場合、中継証明書を信頼リストに追加するか中継を解除します。
7) IPv4/IPv6で異なる証明書を返す構成
同一ホストでもIPv4とIPv6で別のサーバーに到達し、異なる証明書が返ることがあります。両方の経路で証明書を確認してください。
8) Python環境や依存パッケージの問題
requestsやurllib3、OpenSSLのバージョンや設定で検証処理が変わります。ライブラリのバージョンとCAバンドルの使用方法を確認してください。
原因切り分けに使えるチェック方法
以下に、certificate_verify_failed の原因を絞り込むための実用的なチェック方法を具体例つきで示します。手順ごとに何を確認するかも書いています。
1) OpenSSLで接続とチェーンを確認する
例:
openssl s_client -connect example.com:443 -servername example.com -showcerts
確認ポイント:Subject(CN)やSubject Alternative Name(SAN)に対象ドメインがあるか、有効期限(Not After)、発行者(Issuer)、チェーンが完全か。最後に表示される「Verify return code: 0 (ok)」が正常の目安です。
2) 個別証明書の内容を確認する
サーバーから取得した証明書ファイルに対して:
openssl x509 -in cert.pem -noout -text
確認ポイント:有効期限、発行者、SAN、拡張キー使用法など。証明書が壊れていないかを見ます。
3) Python側のCAストアとcertifiを確認する
Pythonで使われるCAファイルの場所を確認:
python -c “import certifi; print(certifi.where())”
必要なら更新:pip install –upgrade certifi
またはシステムCAを更新(例:Debian系なら update-ca-certificates)。仮想環境を使っている場合はその環境内で確認してください。
4) プロキシやウイルス対策ソフトの影響を切り分ける
方法:直接ネットワークから接続する、プロキシ設定を外す、別のマシンや別回線で試す。curlで直接試す例:
curl -v –proxy “” https://example.com
AVやプロキシが中間証明書を差し替えていると証明書検証が失敗します。設定を一時的に無効化して動作を確認してください。
5) サーバー側の証明書設定を見直す
中間証明書が正しく送信されているか、順序は適切かを確認します。s_clientの出力に中間証明書が含まれているかを確認し、SSL Labsなどの検査ツールも利用すると分かりやすいです。Webサーバー設定では、通常「fullchain」や中間を連結したファイルを使います。
追加チェック:クライアントの日時が誤っていると期限エラーになります。まずは時刻同期を確認してください。












