https(ssl)接続のpython実装

6002 ワード

今日コードを書く時1つの問題に出会って、数時間のgoogleを使って、基本的にgoogleの検索の前の何ページの内容をすべて1つ1つ見て、問題は最終的に解決しましたが、過程はとても曲がりくねっているので、この過程を覚えて後で参考にします.
理由は次のコードです.
?
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