https(ssl)接続のpython実装
6002 ワード
今日コードを書く時1つの問題に出会って、数時間のgoogleを使って、基本的にgoogleの検索の前の何ページの内容をすべて1つ1つ見て、問題は最終的に解決しましたが、過程はとても曲がりくねっているので、この過程を覚えて後で参考にします.
理由は次のコードです.
?
1
2
もともとこのコードは簡単で、httpsの接続を要求していましたが、以下のエラーを報告しました.
?
1
最初の反応はhttps証明書の問題です.「python ssl」をキーワードにgoogleを使うと、javaのhttpclientコンポーネントのように、requestパッケージをインストールした後、次の世代コードに変更します.
?
1
2
または次のエラーを報告します.
?
1
requestsとurllib 2で報告されたエラー情報は同じであり、TLSベースのsocket接続など、同じ下位api操作に基づいていることがわかります.ここまで来たとき、この問題はpythonコードで書かれている問題ではなく、オペレーティングシステムレベルの設定が間違っているのではないかと疑っていました.shellクライアントで次のテストスクリプトを直接実行します.
?
1
やはり次のようなエラーが発生しました.
?
1
2
ここまでopensslのインストールに問題があるのか、最新バージョンに更新しても同じで、ブラウザでアクセスできるのでopensslではないはずです.Googleを続けます......、SSLサーバに接続するときのSSLのバージョンが間違っているという問題にも遭遇したことがあります.次のコードで異なるSSLバージョンをテストして、この問題ではないかどうかを見てみましょう.
?
1
2
3
4
5
上記の3つのスクリプトを使用して接続状況をテストしたところ、3つ目は正常に接続できることが分かった(-1,2,3、数字のそれぞれコードtlsv 1、sslv 2、sslv 3の3つの異なるSSLバージョン).このhttps接続が存在するサーバがSSLV 3バージョンに基づいていることを説明します.見つかった問題は、pythonコードを書き換える方法がわかりやすいです.
?
1
2
3
4
5
6
7
8
9
urllib 2実装:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
この2つのスキームの原理は、接続プロセッサをカスタマイズし、接続時のsslのバージョン番号を変更することです.
参考記事:http://bugs.python.org/issue11220
https://github.com/kennethreitz/requests/issues/606
理由は次のコードです.
?
1
2
import
urllib2
urllib2.urlopen(
'https://xxxx.com'
)
もともとこのコードは簡単で、httpsの接続を要求していましたが、以下のエラーを報告しました.
?
1
urllib2.URLError:
最初の反応はhttps証明書の問題です.「python ssl」をキーワードにgoogleを使うと、javaのhttpclientコンポーネントのように、requestパッケージをインストールした後、次の世代コードに変更します.
?
1
2
import
requests
requests.get(
'https://xxx.com'
)
または次のエラーを報告します.
?
1
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:140773E8:SSL routines:SSL23_GET_SERVER_HELLO:reason(1000)
requestsとurllib 2で報告されたエラー情報は同じであり、TLSベースのsocket接続など、同じ下位api操作に基づいていることがわかります.ここまで来たとき、この問題はpythonコードで書かれている問題ではなく、オペレーティングシステムレベルの設定が間違っているのではないかと疑っていました.shellクライアントで次のテストスクリプトを直接実行します.
?
1
wget https:
//xxx
.com
やはり次のようなエラーが発生しました.
?
1
2
OpenSSL: error:140773E8:SSL routines:SSL23_GET_SERVER_HELLO:reason(1000)
SSL 。
ここまでopensslのインストールに問題があるのか、最新バージョンに更新しても同じで、ブラウザでアクセスできるのでopensslではないはずです.Googleを続けます......、SSLサーバに接続するときのSSLのバージョンが間違っているという問題にも遭遇したことがあります.次のコードで異なるSSLバージョンをテストして、この問題ではないかどうかを見てみましょう.
?
1
2
3
4
5
curl -1 https:
//xxx
.com
curl -2 https:
//xxx
.com
curl -3 https:
//xxx
.com
上記の3つのスクリプトを使用して接続状況をテストしたところ、3つ目は正常に接続できることが分かった(-1,2,3、数字のそれぞれコードtlsv 1、sslv 2、sslv 3の3つの異なるSSLバージョン).このhttps接続が存在するサーバがSSLV 3バージョンに基づいていることを説明します.見つかった問題は、pythonコードを書き換える方法がわかりやすいです.
?
1
2
3
4
5
6
7
8
9
class
MyAdapter(HTTPAdapter):
def
init_poolmanager(
self
, connections, maxsize):
self
.poolmanager
=
PoolManager(num_pools
=
connections,
maxsize
=
maxsize,
ssl_version
=
ssl.PROTOCOL_SSLv3)
s
=
requests.Session()
s.mount(
'https://'
, MyAdapter())
# https ssl.PROTOCOL_SSLV3
s.get(
'https://xxx.com'
)
urllib 2実装:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# custom HTTPS opener, banner's oracle 10g server supports SSLv3 only
import
httplib, ssl, urllib2, socket
class
HTTPSConnectionV3(httplib.HTTPSConnection):
def
__init__(
self
,
*
args,
*
*
kwargs):
httplib.HTTPSConnection.__init__(
self
,
*
args,
*
*
kwargs)
def
connect(
self
):
sock
=
socket.create_connection((
self
.host,
self
.port),
self
.timeout)
if
self
._tunnel_host:
self
.sock
=
sock
self
._tunnel()
try
:
self
.sock
=
ssl.wrap_socket(sock,
self
.key_file,
self
.cert_file, ssl_version
=
ssl.PROTOCOL_SSLv3)
except
ssl.SSLError, e:
print
(
"Trying SSLv3."
)
self
.sock
=
ssl.wrap_socket(sock,
self
.key_file,
self
.cert_file, ssl_version
=
ssl.PROTOCOL_SSLv23)
class
HTTPSHandlerV3(urllib2.HTTPSHandler):
def
https_open(
self
, req):
return
self
.do_open(HTTPSConnectionV3, req)
# install opener
urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))
if
__name__
=
=
"__main__"
:
r
=
urllib2.urlopen(
"https://ui2web1.apps.uillinois.edu/BANPROD1/bwskfcls.P_GetCrse"
)
print
(r.read())
この2つのスキームの原理は、接続プロセッサをカスタマイズし、接続時のsslのバージョン番号を変更することです.
参考記事:http://bugs.python.org/issue11220
https://github.com/kennethreitz/requests/issues/606