ssl_routines_ssl23_get_server_hello_reason_1112

这是原文的标题

我遇到一个非常棘手的问题,在chrome中打开一个以https开头的网页时出现:

该网站的安全证书不受信任!”,您尝试访问的是 https://*****,但服务器出示的证书是由您计算机的操作系统不信任的实体所颁发。这可能表明服务器已自行生成了安全凭据,Google Chrome 浏览器认为其中的身份信息不可靠;也可能表明攻击者正试图拦截您的通信内容。


我在百度上找了很久没有找到答案,最后在Google上找到了 老外遇到类似问题的一个帖子,最后成功解决

先写我的解决办法:


import urllib.request
url="https://mwanalysis.org"
urllib.request.urlretrieve(url,"D:\")

出现错误,代码加上一行,改为:

import ssl
import urllib.request
url="https://mwanalysis.org"
urllib.request.install_opener(urllib.request.build_opener(urllib.request.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))))
urllib.request.urlretrieve(url,"D:\")

关键是第四行,虽然不懂,但是就是这一行改变了一切


现在把原文贴上,以备后用:


SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)

I've had some problems with ssl lately, here is what I found to be the problem/solution.

Problem

The problem is pretty easy, inability to access https services, mwanalysis.org may serve as an example here.

Python

I was able to reproduce the problem using python(3.2):

import urllib.request
url="https://mwanalysis.org"
a = urllib.request.urlopen(url)
Traceback (most recent call last):
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 1122, in do_open
    h.request(req.get_method(), req.selector, req.data, headers)
  File "/opt/dionaea/lib/python3.2/http/client.py", line 964, in request
    self._send_request(method, url, body, headers)
  File "/opt/dionaea/lib/python3.2/http/client.py", line 1002, in _send_request
    self.endheaders(body)
  File "/opt/dionaea/lib/python3.2/http/client.py", line 960, in endheaders
    self._send_output(message_body)
  File "/opt/dionaea/lib/python3.2/http/client.py", line 805, in _send_output
    self.send(msg)
  File "/opt/dionaea/lib/python3.2/http/client.py", line 743, in send
    self.connect()
  File "/opt/dionaea/lib/python3.2/http/client.py", line 1105, in connect
    server_hostname=server_hostname)
  File "/opt/dionaea/lib/python3.2/ssl.py", line 168, in wrap_socket
    _context=self)
  File "/opt/dionaea/lib/python3.2/ssl.py", line 254, in __init__
    raise x
  File "/opt/dionaea/lib/python3.2/ssl.py", line 250, in __init__
    self.do_handshake()
  File "/opt/dionaea/lib/python3.2/ssl.py", line 429, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [Errno 1] _ssl.c:390: error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)
    
During handling of the above exception, another exception occurred:
    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 138, in urlopen
    return opener.open(url, data, timeout)
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 366, in open
    response = self._open(req, data)
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 384, in _open
    '_open', req)
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 344, in _call_chain
    result = func(*args)
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 1156, in https_open
    context=self._context, check_hostname=self._check_hostname)
  File "/opt/dionaea/lib/python3.2/urllib/request.py", line 1125, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [Errno 1] _ssl.c:390: error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)>


curl

Curl suffered the same problem:

curl -vvv "https://mwanalysis.org"
* About to connect() to mwanalysis.org port 443 (#0)
*   Trying 131.188.31.200... connected
* Connected to mwanalysis.org (131.188.31.200) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)
* Closing connection #0
curl: (35) error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)


Solution

Python

For Python it is possible to provide a context to the urllib.request.HTTPSHandler and use this ssl context instead of the reasonable default:

# ...
    class HTTPSConnection(HTTPConnection):
# ...
        def __init__(self, host, port=None, key_file=None, cert_file=None,
                     strict=_strict_sentinel, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
                     source_address=None, *, context=None, check_hostname=None):
# ...
            if context is None:
                # Some reasonable defaults
                context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                context.options |= ssl.OP_NO_SSLv2
# ...


To use this with urllib:

import ssl
import urllib.request
url="https://mwanalysis.org"
urllib.request.install_opener(urllib.request.build_opener(urllib.request.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))))
a = urllib.request.urlopen(url)

In case you use tor via privoxy:

import ssl
import urllib.request
url="https://mwanalysis.org"
urllib.request.install_opener(urllib.request.build_opener(urllib.request.ProxyHandler({"http":"http://127.0.0.1:8118"}),
urllib.request.build_opener(urlliburllib.request.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))))
a = urllib.request.urlopen(url)


wget

Interestingly wget works fine for me

wget --no-check-certificate -O /dev/null https://mwanalysis.org
Resolving mwanalysis.org... 131.188.31.200
Connecting to mwanalysis.org|131.188.31.200|:443... connected.
WARNING: cannot verify mwanalysis.org's certificate, issued by `/C=DE/ST=Baden-Wuerttemberg/L=Mannheim/O=Universitaet Mannheim/OU=Rechenzentrum/CN=RUM-CA-G Zertifizierungsinstanz/emailAddress=rum-ca@rz.uni-mannheim.de':
  Unable to locally verify the issuer's authority.
HTTP request sent, awaiting response... 200 OK
Length: 4511 (4.4K) [text/html]
Saving to: `/dev/null'
 
100%[===========================================================================>] 4,511       --.-K/s   in 0s

even with SSLv23_client_method:

bool
ssl_init ()
{
  SSL_METHOD *meth;
// ...
  switch (opt.secure_protocol)
    {
    case secure_protocol_auto:
      meth = SSLv23_client_method ();
      break;
#ifndef OPENSSL_NO_SSL2
    case secure_protocol_sslv2:
      meth = SSLv2_client_method ();
      break;
#endif
    case secure_protocol_sslv3:
      meth = SSLv3_client_method ();
      break;
    case secure_protocol_tlsv1:
      meth = TLSv1_client_method ();
      break;
    default:
      abort ();
    }
  
  ssl_ctx = SSL_CTX_new (meth);


The Problem

Wireshark showed some differences when using curl with -tls1/-ssl3 or no option at all. In case of no option at all, it would have openssl sent a TLSv1 Record Layer: Handshake Protocol: Client Hello with the Extension: "server_name", and the server would respond with an TLSv1 Record Layer: Alert (Level: Warning, Description: Unrecognized Name), causing the client to abort.
Using -tls1, curl would fail the same as it fails for no option.
Using -ssl3, curl would sent the SSLv3 Record Layer: Handshake Protocol: Client Hello without the server_name extension.
Python with the defined opener for TLSv1 will sent the server_name extension, receive the TLSv1 Record Layer: Alert (Level: Warning, Description: Unrecognized Name) but ignore it somewhere.
wget does not set the server_name extension, does not receive an Alert and works fine by default therefore.

The OpenSSL version used on my side is “OpenSSL 0.9.8o 01 Jun 2010”.







posted @ 2013-01-02 00:12  完美视界  阅读(1282)  评论(0编辑  收藏  举报