कुछ साइटों पर पायथन HTTPS अनुरोध (urllib2) प्रॉक्सी के बिना Ubuntu 12.04 पर विफल हो जाते हैं


23

मेरे पास एक छोटा सा ऐप है जिसे मैंने पायथन में लिखा था और यह काम करता था ... कल तक, जब यह अचानक मुझे HTTPS कनेक्शन में एक त्रुटि देने लगा। मुझे याद नहीं है कि कोई अपडेट था, लेकिन पायथन 2.7.3rc2 और पायथन 3.2 दोनों एक ही तरह से विफल हो रहे हैं।

मैंने इसे googled और पता लगाया कि ऐसा तब होता है जब लोग एक प्रॉक्सी के पीछे होते हैं, लेकिन मैं (और आखिरी बार जब यह काम किया था तब से मेरे नेटवर्क में कुछ भी नहीं बदला है)। मेरे सिस्टर के कंप्यूटर पर चलने वाली विंडोज़ और पायथन 2.7.2 में कोई समस्या नहीं है (उसी नेटवर्क में)।

>>> url = 'https://www.mediafire.com/api/user/get_session_token.php'
>>> response = urllib2.urlopen(url).read()
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1215, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1177, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 8] _ssl.c:504: EOF occurred in violation of protocol>

क्या गलत है? किसी भी मदद की सराहना की है।

पुनश्च: पुराने अजगर संस्करण या तो काम नहीं करते हैं, मेरे सिस्टम में नहीं हैं और यूएसबी से लाइव सत्र में नहीं हैं, लेकिन एक Ubuntu 11.10 लाइव सत्र में काम करते हैं।


1
क्या यह हर उस एसएसएल साइट के लिए होता है जिसे आप संपर्क करने की कोशिश करते हैं, या सिर्फ एक? यदि यह हर साइट के लिए नहीं होता है, तो क्या आप हमें बता सकते हैं कि कौन सी साइट समस्या पैदा कर रही है?
जेम्स हेनस्ट्रिज

खैर, मैं खुद एक अनुभवी प्रोग्रामर नहीं हूं, और मैं किसी साइट के एपीआई से एक पृष्ठ को पढ़ने की कोशिश कर रहा हूं, और यह एकमात्र कॉल है जिसे एसएसएल की आवश्यकता होती है, इसलिए मुझे नहीं पता कि क्या मैं इसे पहली जगह में कर रहा था । मैं इसे एक सामान्य urllib.urlopen (url) .read () कॉल की तरह उपयोग कर रहा हूं और यह काम कर रहा था। क्या आप मुझे एक अन्य साइट का पता या एक अजगर स्क्रिप्ट दे सकते हैं जो इस प्रश्न का उत्तर देगा?
पाब्लो

ओह, मैं उल्लेख करना भूल गया: साइट Mediafire है। यह इसका get_session_token कॉल है जो समस्या पैदा कर रहा है।
पाब्लो

मैं इसे उस साइट के साथ पुन: पेश करने में सक्षम था। मैंने आपके प्रश्न को साइट को प्रश्न में शामिल करने के लिए अद्यतन किया है। मुझे संदेह है कि यह ओपनएसएसएल के साथ एक समस्या है, क्योंकि विग भी विफल हो जाती है।
जेम्स हेनस्ट्रिज

यह लेखन के समय मेरे लिए stream.twitter.com के साथ होता है।
मार्क

जवाबों:


15

यह टीएलएस 1.1 और 1.2 के समर्थन से संबंधित प्रतीत होता है जो 12.04 में पाए गए ओपनएसएसएल के संस्करण को सपोर्ट करता है। कनेक्शन की विफलता को ओपनएसएसएल कमांड लाइन टूल के साथ पुन: प्रस्तुत किया जा सकता है:

$ openssl s_client -connect www.mediafire.com:443
CONNECTED(00000003)
140491065808544: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 320 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

कनेक्शन सफल होता है अगर मैं कनेक्शन को -tls1कमांड लाइन तर्क के साथ टीएलएस 1.0 का उपयोग करने के लिए मजबूर करता हूं ।

मैं आपको इस समस्या के बारे में एक बग रिपोर्ट दर्ज करने का सुझाव दूंगा:

https://bugs.launchpad.net/ubuntu/+filebug


2
धन्यवाद! मैंने एक बग की सूचना दी। कृपया, देखें कि क्या आप इसमें कोई प्रासंगिक जानकारी जोड़ सकते हैं: bugs.launchpad.net/ubuntu/+source/openssl/+bug/965371
पाब्लो

1
यह उसे पायथन में समस्या के आसपास काम करने में कैसे मदद करता है?
Cerin

2
@ केरिन: इसने पाइथन में किसी चीज़ के बजाय एक ओपनएसएसएल बग के रूप में समस्या को अलग किया, और उसे बग ट्रैकर का उपयोग करने के लिए निर्देशित किया। यह समस्या तब से तय है।
जेम्स हेनस्ट्रिज सेप

12

मेरे जैसे अजगर नौसिखियों के लिए, यहाँ सबसे आसान तरीका है नेलपॉलिश को ओवरराइड करने का तरीका। अपने अजगर लिपि के शीर्ष पर, इन पंक्तियों को शामिल करें:


import httplib
from httplib import HTTPConnection, HTTPS_PORT
import ssl

class HTTPSConnection(HTTPConnection):
    "This class allows communication via SSL."
    default_port = HTTPS_PORT

    def __init__(self, host, port=None, key_file=None, cert_file=None,
            strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
            source_address=None):
        HTTPConnection.__init__(self, host, port, strict, timeout,
                source_address)
        self.key_file = key_file
        self.cert_file = cert_file

    def connect(self):
        "Connect to a host on a given (SSL) port."
        sock = socket.create_connection((self.host, self.port),
                self.timeout, self.source_address)
        if self._tunnel_host:
            self.sock = sock
            self._tunnel()
        # this is the only line we modified from the httplib.py file
        # we added the ssl_version variable
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1)

#now we override the one in httplib
httplib.HTTPSConnection = HTTPSConnection
# ssl_version corrections are done

यहाँ से, आप urllib या जो कुछ भी आप का उपयोग करते हैं जैसे आप सामान्य रूप से करेंगे।

नोट: यह अजगर 2.7 के लिए है। एक अजगर 3.x समाधान के लिए, आपको http.client में पाए जाने वाले HTTPSConnection वर्ग को ओवरराइड करना होगा। मैं पाठक के लिए एक अभ्यास के रूप में छोड़ देता हूं। :-)


2
मैं वास्तव में इस समाधान को पसंद करता हूं, यह किसी भी सिस्टम लाइब्रेरी या अन्य हैकरी को संशोधित करने से बचता है।
मार्क

4
Ubuntu 12.04 पर पायथन 2.7.4 का उपयोग करने में विफल: NameError: नाम 'सॉकेट' परिभाषित नहीं है। --- आपको "आयात सॉकेट" भी जोड़ना होगा।
बेन वाल्थर

उबंटू 13.04 पर शानदार काम करता है। धन्यवाद!
धर्मटेक

2
केवल पैच करने का कोई कारण नहीं है httplib। लोग अन्य एसएसएल सॉकेट का उपयोग कर सकते हैं। sslनीचे मेरे जवाब के रूप में बजाय पैच सकता है ।
टेम्पो

यह मुझे त्रुटि देता हैBadStatusLine: ''
सेरिन सेप

8

आप अपने HTTPSConnection ऑब्जेक्ट को संशोधित करके CANplib.py फ़ाइल को संशोधित करने से बच सकते हैं:

import httplib, ssl, socket

conn = httplib.HTTPSConnection(URL.hostname)
sock = socket.create_connection((conn.host, conn.port), conn.timeout, conn.source_address)
conn.sock = ssl.wrap_socket(sock, conn.key_file, conn.cert_file, ssl_version=ssl.PROTOCOL_TLSv1)
conn.request('POST', URL.path + URL.query)

अनुरोध विधि केवल एक नया सॉकेट बनाती है यदि कनेक्शन.स्कॉक परिभाषित नहीं है। Ssl_version पैरामीटर को जोड़कर अपना स्वयं का बनाना अनुरोध विधि का उपयोग करेगा। फिर बाकी सब कुछ हमेशा की तरह काम करता है।

मैं एक ही मुद्दा रहा था और यह मेरे लिए काम करता है।

सादर


7

समस्या sslयह है कि इसका HTTP से कोई लेना-देना नहीं है, इसलिए httplibयदि आप पैच कर सकते हैं तो पैचिंग क्यों ssl। निम्नलिखित कोड सहित सभी एसएसएल सॉकेट्स को ठीक करना चाहिए, लेकिन HTTPS तक सीमित नहीं है, पाइथन 2.6+ के लिए (इसमें निर्मित ssl, के साथ प्रयास नहीं किया गया pyopenssl)।

import functools
import ssl

old_init = ssl.SSLSocket.__init__

@functools.wraps(old_init)
def ubuntu_openssl_bug_965371(self, *args, **kwargs):
  kwargs['ssl_version'] = ssl.PROTOCOL_TLSv1
  old_init(self, *args, **kwargs)

ssl.SSLSocket.__init__ = ubuntu_openssl_bug_965371

अच्छा उत्तर। समस्या को हल करने का अच्छा, सुरुचिपूर्ण तरीका।
chnrxn

3

EDIT CANplib.py (/usr/lib/pythonX.X/httplib.py लिनक्स पर)

HTTPSConnection वर्ग घोषणा की खोज करें

  class HTTPSConnection(HTTPConnection):
....

वर्ग कोड CHANGE लाइन के अंदर

self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)

सेवा मेरे

self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1)

फिर कैनप्लिब HTTPS अनुरोध पर काम करना चाहिए

import httplib
from urlparse import urlparse
url = XXX
URL = urlparse(url)
connection = httplib.HTTPSConnection(URL.hostname)
connection.request('POST', URL.path + URL.query)
response = connection.getresponse()

3
यह वास्तव में इस तरह से एक सिस्टम फ़ाइल को संपादित करने का अधिकार नहीं है। इसके बजाय, किसी भी परिभाषा को फिर से परिभाषित करें, जिसे आपके कोड में उन्हें फिर से परिभाषित करके बदलना होगा ।
मोनिका को बहाल करें - 13--

2

SSLv2 वेब सर्वर पर अक्षम होने के कारण यह समस्या होने की संभावना है, लेकिन Python 2.x डिफ़ॉल्ट रूप से PROTOCOL_SSLv23 के साथ एक कनेक्शन स्थापित करने का प्रयास करता है।

स्टैक ओवरफ्लो पर इसी तरह के मुद्दे के लिए मेरे जवाब का लिंक यहां दिया गया है - /programming//a/24166498/41957

अपडेट: यह कार्यात्मक रूप से @ temoto के उत्तर के समान है।


TypeError: अनबाउंड विधि __init __ () को पहले तर्क के रूप में SSLSocket उदाहरण के साथ कहा जाना चाहिए (इसके बजाय _socketobject उदाहरण मिला)
sureshvv

हम्म, आंशिक () वर्ग विधियों के लिए काम नहीं करता है। शीघ्र ही एक बेहतर समाधान पोस्ट करेंगे।
chnrxn

@ सुरेशव, यदि आप समाधान की जांच करने में मदद कर सकते हैं तो इसकी सराहना की जाएगी।
chnrxn

@ टेम्पो के जवाब ने काम किया।
सुरेशव

1

मेरे लिए काम करने वाला एक साधारण सुधार एसएसएल के डिफ़ॉल्ट प्रोटोकॉल को ओवरराइड करना था:

import ssl
ssl.PROTOCOL_SSLv23 = ssl.PROTOCOL_TLSv1

यह हैकिश है, लेकिन यह आज के संदर्भ में अच्छी तरह से काम करता है। जब से पूडल भेद्यता का पता चला है, TLSv1 बहुत अधिक इंटरनेट पर केवल स्वीकार्य संस्करण बन गया है।
chnrxn
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.