SSL証明書の検証Python
-
23-08-2019 - |
質問
私は書く必要があるスクリプトに接続するバンチのサイトに当社の企業イントラネットのHTTPS通信を検証し、そのSSL証明書の有効;その終了せず、その発行のための正しいアドレスなどをいいます。しての利用の有無に関わらず、社内の企業証明書発行局のためにこれらのサイトをしておりますので、公開鍵、CAの証明書。
PythonによるデフォルトではSSL証明書がHTTPSを使用する場合でも証明書が無効になってライブラリなどurllib2ねますので楽しく使用の証明書。
り良い図書館をどこかにするように接続し、サイトのHTTPS通信および内容を確認するための証明書こう。
どうか検証する証明書Python?
解決
リリースバージョン2.7.9 / 3.4.3からPythonの、上には、 に、デフォルトで証明書の検証を実行しようとします。
ます。https://www.pythonこれは読む価値である、PEP 467で提案されています。組織は/ dev /のPEP / PEP-0476 /
のの変化が(urllibは/ urllib2のは、http、httplib)すべての関連STDLIBモジュールに影響を与えます。
関連ドキュメンテーションます:
https://docs.python.org/2/library/httplib.html#httplib .HTTPSConnectionする
このクラスは、デフォルトですべての必要な証明書とホスト名のチェックを行います。以前、未検証、動作ssl._create_unverified_contextに戻す()コンテキストパラメータに渡すことができます。
https://docs.python.org/3/library/http .client.html#http.client.HTTPSConnectionする
バージョン3.4.3で変更:このクラスは、デフォルトですべての必要な証明書とホスト名のチェックを行います。以前、未検証、動作ssl._create_unverified_contextに戻す()コンテキストパラメータに渡すことができます。
新しい組み込みの検証は、のシステム提供の証明書データベースに基づいていることに注意してください。 のパッケージ船を独自の証明書バンドル要求は、それに反対しました。両方のアプローチの長所と短所は、の 信託データベースの節に記載されていますPEP 476 のます。
他のヒント
私は、Pythonの以前のバージョンで利用可能なのPython 3.2 match_hostname()
パッケージからssl
機能させるのPythonパッケージインデックスへの配布を追加した。
http://pypi.python.org/pypi/backports.ssl_match_hostname/ の
あなたがして、それをインストールすることができます:
pip install backports.ssl_match_hostname
それとも、それをプロジェクトのsetup.py
に記載されている依存することができます。いずれかの方法では、それはこのように使用することができます:
from backports.ssl_match_hostname import match_hostname, CertificateError
...
sslsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv3,
cert_reqs=ssl.CERT_REQUIRED, ca_certs=...)
try:
match_hostname(sslsock.getpeercert(), hostname)
except CertificateError, ce:
...
あなたは、証明書を確認するためにツイストを使用することができます。主なAPIがあることができ、 CertificateOptions のですそのような listenSSLなどの様々な機能にcontextFactory
引数として提供と STARTTLS に。
PycURL この美しく。
以下は一例です。をスローします、 pycurl.error
うに、怪し、すタプルデータ抽出処理がエラーコードと人間が読める形式のメッセージ。
import pycurl
curl = pycurl.Curl()
curl.setopt(pycurl.CAINFO, "myFineCA.crt")
curl.setopt(pycurl.SSL_VERIFYPEER, 1)
curl.setopt(pycurl.SSL_VERIFYHOST, 2)
curl.setopt(pycurl.URL, "https://internal.stuff/")
curl.perform()
おそらく設定したいオプションのような場所に店の結果などがある。らなくても、クラッタの例外にあります。
というものを考えて、例外が十分にあると判断すれば:
(60, 'Peer certificate cannot be authenticated with known CA certificates')
(51, "common name 'CN=something.else.stuff,O=Example Corp,C=SE' does not match 'internal.stuff'")
いくつかのリンクから役に立つの国際化ファイルを含ドクのためのsetoptとgetinfo.
ここでは、証明書の検証を示す例のスクリプトは次のとおりです。
import httplib
import re
import socket
import sys
import urllib2
import ssl
class InvalidCertificateException(httplib.HTTPException, urllib2.URLError):
def __init__(self, host, cert, reason):
httplib.HTTPException.__init__(self)
self.host = host
self.cert = cert
self.reason = reason
def __str__(self):
return ('Host %s returned an invalid certificate (%s) %s\n' %
(self.host, self.reason, self.cert))
class CertValidatingHTTPSConnection(httplib.HTTPConnection):
default_port = httplib.HTTPS_PORT
def __init__(self, host, port=None, key_file=None, cert_file=None,
ca_certs=None, strict=None, **kwargs):
httplib.HTTPConnection.__init__(self, host, port, strict, **kwargs)
self.key_file = key_file
self.cert_file = cert_file
self.ca_certs = ca_certs
if self.ca_certs:
self.cert_reqs = ssl.CERT_REQUIRED
else:
self.cert_reqs = ssl.CERT_NONE
def _GetValidHostsForCert(self, cert):
if 'subjectAltName' in cert:
return [x[1] for x in cert['subjectAltName']
if x[0].lower() == 'dns']
else:
return [x[0][1] for x in cert['subject']
if x[0][0].lower() == 'commonname']
def _ValidateCertificateHostname(self, cert, hostname):
hosts = self._GetValidHostsForCert(cert)
for host in hosts:
host_re = host.replace('.', '\.').replace('*', '[^.]*')
if re.search('^%s$' % (host_re,), hostname, re.I):
return True
return False
def connect(self):
sock = socket.create_connection((self.host, self.port))
self.sock = ssl.wrap_socket(sock, keyfile=self.key_file,
certfile=self.cert_file,
cert_reqs=self.cert_reqs,
ca_certs=self.ca_certs)
if self.cert_reqs & ssl.CERT_REQUIRED:
cert = self.sock.getpeercert()
hostname = self.host.split(':', 0)[0]
if not self._ValidateCertificateHostname(cert, hostname):
raise InvalidCertificateException(hostname, cert,
'hostname mismatch')
class VerifiedHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, **kwargs):
urllib2.AbstractHTTPHandler.__init__(self)
self._connection_args = kwargs
def https_open(self, req):
def http_class_wrapper(host, **kwargs):
full_kwargs = dict(self._connection_args)
full_kwargs.update(kwargs)
return CertValidatingHTTPSConnection(host, **full_kwargs)
try:
return self.do_open(http_class_wrapper, req)
except urllib2.URLError, e:
if type(e.reason) == ssl.SSLError and e.reason.args[0] == 1:
raise InvalidCertificateException(req.host, '',
e.reason.args[1])
raise
https_request = urllib2.HTTPSHandler.do_request_
if __name__ == "__main__":
if len(sys.argv) != 3:
print "usage: python %s CA_CERT URL" % sys.argv[0]
exit(2)
handler = VerifiedHTTPSHandler(ca_certs = sys.argv[1])
opener = urllib2.build_opener(handler)
print opener.open(sys.argv[2]).read()
それとも単に要求を使用することによって、あなたの人生を容易にするライブラリます:
import requests
requests.get('https://somesite.com', cert='/path/server.crt', verify=True)
その使用状況について M2Crypto にすることができます<のhref = "http://www.heikkitoivonen.net/blog/ 10分の2008/14 / SSLインのpython-26 /」のrel = "nofollowをnoreferrer">検証を行います。あなたが好きな場合にも、ツイストするで M2Cryptoを使用することができます。 チャンドラーのデスクトップクライアントは、ネットワーキングとM2Cryptoのためのツイストを使用しています証明書の検証を含め、SSL のます。
グリフに基づいてM2CryptoがあまりにものsubjectAltNameフィールドをチェックするためM2Cryptoは、あなたが現在pyOpenSSLで何ができるかよりも、デフォルトでは、より良い証明書の検証を行うようにそれはそうコメントしています。
私はまた、どのように<のhref =「http://www.heikkitoivonen.net/blog/2008/09/30/root-certificates-for-python-programs-using-python/」RELにブログましたPythonのSSLソリューションとPythonでと使用可能に= "nofollowをnoreferrer"> Mozilla Firefoxの船の証明書を取得します。
Jythonのは、例えば、その標準ライブラリモジュールを使用して、デフォルトで証明書の検証を実施んhttplib.HTTPSConnectionなど、jythonのでは、証明書を確認し、障害の例外を与える、などすなわち不一致のアイデンティティ、期限切れの本命、されます。
実際には、あなたは本命を検証しないようにJythonのを取得するために、すなわち、CPythonのように振る舞うようにJythonのを取得するために、いくつかの余分な作業をしなければなりません。
私はそれがテスト段階などにおいて有用である可能性があるため、Jythonの上のチェック証明書を無効にする方法についてブログ記事を書いています。
JavaおよびJythonの上のすべての-信頼のセキュリティプロバイダをインストールする。
ます。http://jython.xhaus。 COM /インストール-・オール・信頼・セキュリティ・プロバイダオンのjava-と、Jythonの/ の
次のコードは、例えば、プラグイン可能な検証ステップを除くすべてのSSL検証チェック(例えば日付の妥当性、CA証明書チェーン...)の恩恵を受けることができますホスト名を確認したり、他の追加の証明書検証の手順を実行します。
from httplib import HTTPSConnection
import ssl
def create_custom_HTTPSConnection(host):
def verify_cert(cert, host):
# Write your code here
# You can certainly base yourself on ssl.match_hostname
# Raise ssl.CertificateError if verification fails
print 'Host:', host
print 'Peer cert:', cert
class CustomHTTPSConnection(HTTPSConnection, object):
def connect(self):
super(CustomHTTPSConnection, self).connect()
cert = self.sock.getpeercert()
verify_cert(cert, host)
context = ssl.create_default_context()
context.check_hostname = False
return CustomHTTPSConnection(host=host, context=context)
if __name__ == '__main__':
# try expired.badssl.com or self-signed.badssl.com !
conn = create_custom_HTTPSConnection('badssl.com')
conn.request('GET', '/')
conn.getresponse().read()
pyOpenSSL のOpenSSLライブラリへのインターフェースです。それはあなたが必要なすべてを提供する必要があります。
私は同じ問題を抱えてますが(この一回限りのスクリプトは、多くのユーザーによって実行されることになっていたので)、サードパーティの依存関係を最小限にしたかったです。私のソリューションは、curl
呼び出しをラップし、終了コードが0
れたことを確認しました。魔法のように働いています。