在这一天中度过了一天的大部分时间,我真的在我的智慧结束。我安装了1台装有Python 2.6.6 / 2.7.2的机器“A”,安装了Python 2.6.7 / 2.7.2的另一台机器“B”。
在计算机A 上,我可以使用Python 2.6.6获得SSLv3加密的网站urllib2.urlopen('https://fed.princeton.edu')
,但不能使用2.7.2。
在机器B 上,我无法使用Python版本获取该网站。
由于无法得到,我的意思是我得到错误:
Traceback:
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django_cas-2.0.3-py2.7.egg/django_cas/views.py" in login
78. user = auth.authenticate(ticket=ticket, service=service)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/contrib/auth/__init__.py" in authenticate
55. user = backend.authenticate(**credentials)
File "/usr/local/lib/python2.7/dist-packages/django_cas-2.0.3-py2.7.egg/django_cas/backends.py" in authenticate
72. username = _verify(ticket, service)
File "/usr/local/lib/python2.7/dist-packages/django_cas-2.0.3-py2.7.egg/django_cas/backends.py" in _verify_cas2
46. page = urlopen(url)
File "/usr/lib/python2.7/urllib.py" in urlopen
84. return opener.open(url)
File "/usr/lib/python2.7/urllib.py" in open
205. return getattr(self, name)(url)
File "/usr/lib/python2.7/urllib.py" in open_https
435. h.endheaders(data)
File "/usr/lib/python2.7/httplib.py" in endheaders
954. self._send_output(message_body)
File "/usr/lib/python2.7/httplib.py" in _send_output
814. self.send(msg)
File "/usr/lib/python2.7/httplib.py" in send
776. self.connect()
File "/usr/lib/python2.7/httplib.py" in connect
1161. self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
File "/usr/lib/python2.7/ssl.py" in wrap_socket
372. ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py" in __init__
134. self.do_handshake()
File "/usr/lib/python2.7/ssl.py" in do_handshake
296. self._sslobj.do_handshake()
Exception Type: IOError at /login
Exception Value: [Errno socket error] [Errno 1] _ssl.c:503: error:140773F2:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert unexpected message
首先,我很困惑,在早期的Python版本上工作的东西在机器A上的后期工作不起作用。我也很困惑,2.6.6上工作的东西在2.6上不起作用。 7(虽然在不同的机器上)。为什么会这样?
现在我不确定Python的配置是否完全相同,但import _ssl
和import httplib; httplib.HTTPSConnection
适用于两台机器上的所有版本。我在两台机器上都尝试了curl -v https://fed.princeton.edu
和openssl fed.princeton.edu:https
,这些命令都可以正常工作。
我也做了一些研究,发现How to use urllib2 to get a webpage using SSLv3 encryption作者似乎放弃了urllib的libCurl(我宁愿不要因为我使用的是django-cas,它使用的是urllib而且我不喜欢我不想过多地使用那些代码。
注意:我刚刚找到http://bugs.python.org/issue11220,最后一个帖子的解决方案允许我使用urlopen打开网站。但是我如何使用他们的解决方案(似乎是使用urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))
?)来解决django-cas中的urlopen()?
答案 0 :(得分:6)
经过一些实验后,我刚接受Python 2.6.6没问题,但2.6.7+有这个错误,无法通过urllib.urlopen()
获取SSLv3加密的页面。
我通过简单地使用http://bugs.python.org/issue11220上的urllib2.install_opener
技巧解决了我的问题,并修改了django_cas,以便在任何urlopen()
调用之前安装此开启工具。
答案 1 :(得分:0)
您可以通过覆盖ssl_version关键字参数来修补ssl.wrap_socket()。以下代码可以按原样使用。把这个放在urlopen()之前。
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)
编辑:我在意识到functools.partial没有实际返回函数后更新了上面的代码,在这种情况下不适合。看起来很粗糙,上面的代码仍然是我目前所知的最佳解决方案。