Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
40
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@orangain

macOS用公式インストーラーのPython 3.6でCERTIFICATE_VERIFY_FAILEDとなる問題

この記事の内容はインストーラーの大切な情報にすべて書いてありますが、気づかないとハマるので残しておきます。

Pythonインストーラーの大切な情報

問題

python.orgで配布されているmacOS用の公式インストーラーでインストールしたPython 3.6を使い、urllib.request.urlopen()https://のWebページを取得しようとすると、以下のエラーが発生します。

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1318, in do_open
    encode_chunked=req.has_header('Transfer-encoding'))
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1026, in _send_output
    self.send(msg)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 964, in send
    self.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1400, in connect
    server_hostname=server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 401, in wrap_socket
    _context=self, _session=session)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 808, in __init__
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 1061, in do_handshake
    self._sslobj.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 683, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 223, in urlopen
    return opener.open(url, data, timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 526, in open
    response = self._open(req, data)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 544, in _open
    '_open', req)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 504, in _call_chain
    result = func(*args)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1361, in https_open
    context=self._context, check_hostname=self._check_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1320, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)>

他にもsslモジュールを使うモジュールではサーバー証明書の検証時に同様のエラーが発生するはずです。

原因

macOSに標準でインストールされているOpenSSLが古すぎるため、Python 3.6以降ではmacOS用のインストーラーにはOpenSSLが同梱され、システムのOpenSSLは参照されなくなりました。

これによって、OSにインストールされたルート証明書も参照されず、インストール直後の状態ではルート証明書が含まれていません1。このため、TLSサーバー証明書の検証に失敗します。

対処法

以下のコマンドを実行すると、certifiモジュールをダウンロードしそこに含まれるルート証明書を参照するようになります。

$ /Applications/Python\ 3.6/Install\ Certificates.command

実行前:

$ ls -l /Library/Frameworks/Python.framework/Versions/3.6/etc/openssl/

実行後:

$ ls -l /Library/Frameworks/Python.framework/Versions/3.6/etc/openssl/
total 8
lrwxr-xr-x  1 orange  admin  52  3 22 23:00 cert.pem -> ../../lib/python3.6/site-packages/certifi/cacert.pem

この場合、ルート証明書の更新に応じて適切にアップデートするために、certifiプロジェクトのメーリングリストを購読しましょうと書かれています。

今後

ユーザーが個別に証明書をアップデートしなければならない今の状態は望ましくないので、DSAS開発者の部屋:最近の Python-dev (2017-03)にあった、OpenSSL以外のTLS実装を使ってOSの証明書を利用できるようにするPEP 543の話につながっていくのだと思います。

参考


  1. pipはルート証明書を同梱しているので、pip installは動きます。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
40
Help us understand the problem. What are the problem?