10

花了一天的大部分时间在这上面,我真的不知所措。我有一台安装了 Python 2.6.6/2.7.2 的机器“A”,另一台安装了 Python 2.6.7/2.7.2 的机器“B”。

在机器 Aurllib2.urlopen('https://fed.princeton.edu')上,我可以使用 Python 2.6.6 而不是 2.7.2获得 SSLv3 加密的网站。

在机器 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 _sslimport httplib; httplib.HTTPSConnection我也在两台机器上都试过了curl -v https://fed.princeton.eduopenssl fed.princeton.edu:https这些命令都可以工作。

我也做了一些研究,发现如何使用 urllib2 来获取使用 SSLv3 加密的网页,作者似乎已经放弃了 urllib 用于 libCurl(我宁愿不使用,因为我使用的是 django-cas,它使用 urllib而且我不想过多地摆弄该代码)。


注意:我刚刚找到http://bugs.python.org/issue11220,最后一个帖子的解决方案允许我使用 urlopen 打开网站。但是我如何使用他们的解决方案(似乎是使用urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))?)来解决我在 django-cas 中的 urlopen() ?

4

2 回答 2

6

经过更多的实验,我刚刚接受 Python 2.6.6 是可以的,但是 2.6.7+ 有这个错误,即无法通过urllib.urlopen().

我通过简单地使用http://bugs.python.org/issue11220urllib2.install_opener的技巧解决了我的问题,并修改了 django_cas 以便在任何调用之前安装这个开启器。urlopen()

于 2012-03-24T03:15:41.200 回答
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 实际上并没有返回函数后,我更新了上面的代码,并且在这种情况下不适合。尽管看起来很笨重,但上面的代码仍然是迄今为止我所知道的最好的解决方案。

于 2014-06-11T08:25:22.563 回答