前提
プログラミング初心者です.
pythonで主にrequestライブラリ,BeautifulSoupライブラリを用いてWEBスクレイピングを作っています.
その中で,SSL証明書の有無を取得しようとしていますが,うまくいっていません.
質問
・下の方法で証明書の有無を確認することは可能か
・もし可能なのであれば,(証明書が無効であるURLを入力したときにNoneと返してもらいたいので)証明書の有効性を確かめないようにしたらいいのではと考えているので,それを実現するにはどのようにコードを修正すればよいか教えていただきたいです.
現状やったこと・コード内容・実行結果について
・getpeercert()を用いて証明書の有無の確認を試みました.公式ドキュメントによると,接続の相手側の証明書がない場合は None を返す関数ということで,Noneがかえってきたら証明書なし,それ以外はありと判別しようと考えました.
・このメソッドはSSLSocketオブジェクトに作用するとのことで,下に記載したコードの4~6行目でまずSSLSocketオブジェクトを作りました.これに対しgetpeercert()を用いて証明書の有無をcert_t,certに代入しました.(このあたりはあまり理解できていません,参考URLの二つ目のコードをコピペしました)
・これを実行すると,SSL証明書のあるURLだとエラーが発生せず証明書が返ってくるのですが,証明書のないURLで試すと以下のエラーがでてしまいます.「証明書が無効だ」という内容のエラーだと思うのですが,そもそも証明書の有効性を確かめるようなコードは書いていないのになぜこのようなエラーが出ているかわかりません.
エラー内容
SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1129)
該当のソースコード
python3
1#SSLの取得 2 3import socket 4import ssl 5 6def get_server_certificate(hostname): 7 context = ssl.create_default_context() # デフォルトの設定を持つ新しい SSLContext オブジェクトを返します 8 with socket.create_connection((hostname, 443)) as sock: # host と port で指定されたアドレスへの接続をオープン 9 with context.wrap_socket(sock, server_hostname=hostname) as sslsock: 10 # 既存のPythonソケット(sock)をコンテキストでラップして、 11 # SSLContext.sslsocket_classのインスタンス(デフォルトはSSLSocket)を返します。 12 13 cert_t = sslsock.getpeercert(True) 14 return (cert_t) 15 16 17# cert = get_server_certificate('www.google.com') # SSL証明書のあるページのURL 18cert = get_server_certificate('www.hibishippo.jp') # SSL証明書のないページのURL 19 20cert 21
試したこと
ブラウザのディベロッパーツールに何かしらの方法でアクセスし、Securityのタブに「valid」の文章があるか判別する方法も検討しましたが,検索してもそういった方法を見つけることができませんでした。
補足情報(FW/ツールのバージョンなど)
Jupyter Notebookを使用しています.
参考にしたURL
・Python公式ドキュメント・getpeercert ()について:
https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert
・参考にしたコード
https://teratail.com/questions/269727
追記:改変したソースコード
「sslで接続を保ててかつ,証明書が有効期限内の場合にTrueを返し,sslで接続を保てない場合にFalseを返す」コードを書いてみたところ,欲しい結果を得ることができました.
python3
1import socket 2import ssl 3import OpenSSL 4 5valid=False 6 7def get_server_certificate(hostname): 8 context = ssl.create_default_context() 9 try: 10 with socket.create_connection((hostname, 443)) as sock: 11 with context.wrap_socket(sock, server_hostname=hostname) as sslsock: 12 der_cert = sslsock.getpeercert(True) 13 return ssl.DER_cert_to_PEM_cert(der_cert),True 14 except: 15 return 0,False 16 17cert = get_server_certificate('qiita.com') 18 19valid=cert[1] 20 21if valid==True: 22 x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert[0].encode('utf-8')) 23 24 import datetime 25 from datetime import datetime as dt 26 not_before = dt.strptime(str(x509.get_notBefore())[2:16],'%Y%m%d%H%M%S') + datetime.timedelta(hours=9) 27 not_after = dt.strptime(str(x509.get_notAfter())[2:16],'%Y%m%d%H%M%S') + datetime.timedelta(hours=9) 28 print(not_after) 29 30 period=not_after - dt.now() 31 32 if period.days>0: 33 valid=True 34 else: 35 valid=False 36valid

回答2件
あなたの回答
tips
プレビュー