【python】SSLCertVerificationErrorになったお話

どーもたかぽんです...!

先ほどDiscordを使っていい感じにbot作ってみよ〜っていうのを試していたのですが、一箇所結構つまづいたところがあったので、それについて書いていこうと思います。

発生したエラー

まず、筆者がつまづいたところなんですが...

簡単にいうとDiscordと接続を確立して、スラッシュコマンドを実装しようとした際、プログラムを動かそうとしてもうまく動かなかったんですね...

雑なイメージだと以下のようなコードがこけてしまっていました。

TOKEN = "DiscordBotToken"
client = discord.Bot()
client.run(TOKEN)

discordapp.comのホストへアクセスする際、certificate verify failedとなり、認証が失敗しているようでした。

ちょっと長くなってしまいますが...実際のエラーは以下になります。

taka@Taka discord % python3 command-bot.py
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/connector.py", line 980, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore[return-value]  # noqa
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 1081, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 1111, in _create_connection_transport
    await waiter
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/sslproto.py", line 528, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/sslproto.py", line 188, in feed_ssldata
    self._sslobj.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/ssl.py", line 944, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/taka/Practice/python/discord/command-bot.py", line 27, in <module>
    client.run(TOKEN)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/client.py", line 717, in run
    return future.result()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/client.py", line 696, in runner
    await self.start(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/client.py", line 659, in start
    await self.login(token)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/client.py", line 514, in login
    data = await self.http.static_login(token.strip())
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/http.py", line 406, in static_login
    data = await self.request(Route("GET", "/users/@me"))
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/discord/http.py", line 280, in request
    async with self.__session.request(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/client.py", line 1141, in __aenter__
    self._resp = await self._coro
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/client.py", line 536, in _request
    conn = await self._connector.connect(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/connector.py", line 540, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/connector.py", line 901, in _create_connection
    _, proto = await self._create_direct_connection(req, traces, timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/connector.py", line 1206, in _create_direct_connection
    raise last_exc
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/connector.py", line 1175, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/aiohttp/connector.py", line 982, in _wrap_create_connection
    raise ClientConnectorCertificateError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host discord.com:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)')]

最初はコードが何か変なのか?と思い、いろんな方のdiscord bot導入周りの情報を見たけどやはり問題はなさそうでした。

エラーの原因と解決方法

さて、エラーの原因ですが...調べていくとこちらのgithubに行きつきました。

openSSL周りの知識があまりないので正確に理解できている自信はないのですが...

python3.6以降, (おそらくMacユーザーのみは)pythonのsslモジュールでは証明書が使用されない様でした。

実際に...

Macintosh HD > Application > Python 3.9

のフォルダ内を探してみると、ReadMe.rtfがあり、下記記載の文言が書かれていました。

// ReadMe.rtfから一部抜粋

This package will install Python 3.9.1 for macOS 10.9 or later for the following architecture(s): arm64, x86_64.

Certificate verification and OpenSSL

This package includes its own private copy of OpenSSL 1.1.1.   
The trust certificates in system and user keychains managed by the 
Keychain Access application and the security command line utility 
are not used as defaults by the Python ssl module. 

 A sample command script is included in /Applications/Python 3.9 to install 
a curated bundle of default root certificates from the third-party certifi package 
(https://pypi.org/project/certifi/).  
Double-click on Install Certificates to run it.

ここを見た感じ、Install Certificatesのファイルをダブルクリックして実行すれば一通り問題ない形に環境が構築されるっぽかったので、同じく"Python 3.9"ファイルにある、"Install Certificates.command"ファイルをダブルクリックすると...

コマンドラインが立ち上がって...

"プロセスが完了しました"と表示されました。

そして、再度先ほどのエラーになったコマンドを実行すると問題なく動作しました。

まとめ

今回はpythonで出会ったエラーについてでした...!

正直自分が書いたコード自体のエラーならまぁわかりやすいんですけど、よくわからないことが急に出るとやっぱり時間かかっちゃいますね...

解決につながった質問へのリンクも載せておきます...!

stack overflowに感謝感謝...

おすすめの記事