私はUbuntu 12.10にOpenSSL 1.0.1c、python 2.7.3、 Requests 1.0.3および1.0.4(両方試してみました)、およびに接続しようとしています次のコードを含むurl変数のウェブサイト。
def SendInitialRequest(xmlmessage, redirecturl):
url = 'https://centineltest.cardinalcommerce.com/maps/txns.asp'
payload = 'cmpi_msg=' + ET.tostring(xmlmessage)
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
r = requests.post(url, data=payload, headers=headers, verify=None)
print r.text
次のエラーがスローされます。
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "clams/libs/centinel/thinclient.py", line 134, in SendInitialRequest
r = requests.post(url, data=payload, headers=headers, verify=None)
File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/api.py", line 87, in post
return request('post', url, data=data, **kwargs)
File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/sessions.py", line 269, in request
resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/sessions.py", line 364, in send
r = adapter.send(request, **kwargs)
File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/adapters.py", line 163, in send
raise SSLError(e)
requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocol
Opensslで接続しようとすると、次の結果が返されます。
$ openssl s_client -connect centineltest.cardinalcommerce.com:443
CONNECTED(00000003)
140019346777760:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 226 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
Tls1を使用するように強制すると、動作します(出力は切り捨てられます):
$ openssl s_client -tls1 -connect centineltest.cardinalcommerce.com:443
CONNECTED(00000003)
depth=2 C = US, O = "thawte, Inc.", OU = Certification Services Division, OU
verify error:num=20:unable to get local issuer certificate
verify return:0
---
これについては、多くの バグレポート を見てきました。ただし、pythonリクエストライブラリを使用して回避する方法は見つかりませんでした。どんな援助も大歓迎です。
リクエストは、バージョン1より前のバージョンではサポートしていません。バージョン1に続いて、次のようにHTTPAdapterをサブクラス化する必要があります。
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
import ssl
class MyAdapter(HTTPAdapter):
def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(num_pools=connections,
maxsize=maxsize,
block=block,
ssl_version=ssl.PROTOCOL_TLSv1)
それが終わったら、これを行うことができます:
import requests
s = requests.Session()
s.mount('https://', MyAdapter())
そのセッションオブジェクトを介した要求は、TLSv1を使用します。
Verify = Falseを設定すると、サーバー証明書の検証のみがスキップされますが、SSLプロトコルエラーの解決には役立ちません。
この問題は、WebサーバーでSSLv2が無効になっていることが原因である可能性がありますが、Python 2.xはデフォルトでPROTOCOL_SSLv23との接続を確立しようとします。これは https://github.com/python/cpython/blob/360aa60b2a36f5f6e9e20325efd8d472f7559b1e/Lib/ssl.py#L1057 で発生します
Ssl_versionキーワードパラメーターをオーバーライドすることにより、sslモジュールでssl.wrap_socket()をモンキーパッチできます。次のコードはそのまま使用できます。リクエストを行う前に、これをプログラムの最初に配置してください。
import ssl
from functools import wraps
def sslwrap(func):
@wraps(func)
def bar(*args, **kw):
kw['ssl_version'] = ssl.PROTOCOL_TLSv1
return func(*args, **kw)
return bar
ssl.wrap_socket = sslwrap(ssl.wrap_socket)
requests
の「セキュリティ」パッケージエクストラのインストールは解決しました:
Sudo apt-get install libffi-dev
Sudo pip install -U requests [security]
これは既知のバグです。ハックで回避できます。
site-packages/requests/packages/urllib3/connectionpool.py
を開き(または、独自のプロジェクト内でリクエストのローカルコピーを作成する)、次のブロックを変更します。
def connect(self):
# Add certificate verification
sock = socket.create_connection((self.Host, self.port), self.timeout)
# Wrap socket using verification with the root certs in
# trusted_root_certs
self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=self.cert_reqs,
ca_certs=self.ca_certs,
server_hostname=self.Host,
ssl_version=self.ssl_version)
に:
def connect(self):
# Add certificate verification
sock = socket.create_connection((self.Host, self.port), self.timeout)
# Wrap socket using verification with the root certs in
# trusted_root_certs
self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=self.cert_reqs,
ca_certs=self.ca_certs,
server_hostname=self.Host,
ssl_version=ssl.PROTOCOL_TLSv1)
それ以外の場合は、ハックの少ないオーバーライドがどこかにあると思いますが、一見しただけでは見つけることができませんでした。
NOTE:サイドノートでは、MacOS上のPIP(1.0.4)からのrequests
は、指定したURLで機能します。
上記の修正が機能しない人々に。
ファイルssl.pyを変更して修正する必要がありました。関数create_default_contextを探して、行を変更します。
context = SSLContext(PROTOCOL_SSLv23)
に
context = SSLContext(PROTOCOL_TLSv1)
たぶん、誰かがssl.pyを編集せずに簡単なソリューションを作成できますか?
このエラーが発生しましたが、修正プログラムはSNIをオフにしているようですが、Python 2.7はサポートしていません。
私は同じ問題を抱えていました:
sSLError(e)を発生させます
requests.exceptions.SSLError:[Errno 8] _ssl.c:504:EOFがプロトコルに違反して発生しました
フィドラーを実行していましたが、フィドラーのキャプチャを停止しましたが、このエラーは表示されませんでした。フィドラーのせいかもしれません。
残念ながら、受け入れられた答えは私にはうまくいきませんでした。一時的な回避策として、安全なWebサイトに接続するときにverify=False
を使用することもできます。
From SSLErrorをスローするPythonリクエスト
requests.get('https://example.com', verify=True)
私は同様の問題を抱えていたので、ssl
の検証を単に無視すると、私にとってはうまくいくように、検証は魅力的に機能すると思います。したがって、https
スキームを使用してサーバーに接続しますが、証明書を検証しないように指示します。
requests
を使用します。 None
の代わりにverify=False
とだけ言ってください
requests.post(url, data=payload, headers=headers, verify=False)
これが必要な人に役立つことを願っています:)。
TLS経由でRabbitMQ MQTTサーバーに接続するときにこのエラーが発生しました。サーバーは壊れていると確信していますが、とにかくOpenSSL 1.0.1で動作しましたが、not OpenSSL 1.0.2です。
以下を使用して、Pythonでバージョンを確認できます。
import ssl
ssl.OPENSSL_VERSION
古いバージョンのPythonを使用する以外に、Python(少なくともWindowsでは静的にリンクされているようです)内でOpenSSLをダウングレードする方法がわかりません。