在龙卷风中捕获SSLErrors

时间:2014-11-14 16:03:27

标签: python ssl tornado

我正在使用SSL和自签名证书在Python 2.7.5 virtualenv中运行Tornado 4.0.2,并且以下SSLError会反复出现:

SSLError: [Errno 1] _ssl.c:1419: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca

以下几个问题:

  1. 我假设这些例外是由于客户对我的自签名证书感到不满。这是对的吗?

  2. 假设是这种情况 - 我不关心这个异常,我不想在日志中看到它。 (这是一个内部网络服务器 - 我们永远不会为CA付费。所有连接都必须是不受信任的。)为了尝试自己捕获异常,我尝试按如下方式对IOLoop进行子类化:

    class MyIOLoop(IOLoop):
        def handle_callback_exception(callback):
            print "Exception in callback", callback
    
    if __name__ == "__main__":
        app = Application(urls, compress_response = True)
        ioloop=MyIOLoop.instance()
        http_server = httpserver.HTTPServer(app, ssl_options={"certfile": "cert.pem", "keyfile": "key.pem" }, io_loop=ioloop )
        http_server.listen(8888)
        ioloop.start()
    
  3. 但这没有帮助 - 我仍然得到完整的堆栈跟踪。

    我自己需要做些什么来处理(即忽略)此类异常?我已尝试在ssl_options中设置cert_reqs" : ssl.CERT_NONE,但这也没有帮助。

    1. 当我遇到这样的例外时,我还有什么需要做的 - 比如自己关闭连接吗?如果是,那又怎么样?

2 个答案:

答案 0 :(得分:1)

我也asked this question on the Tornado mailing list,得到了以下回复:

  

此错误来自HTTP1ServerConnection,而不是IOLoop(我想   错误使得它一直到IOLoop这些都是不常见的   天)。你是对的,这意味着客户拒绝了   连接,因为它不信任您的证书。这可以说是有道理的   在这种情况下记录某些东西很有用(你想知道是否这样   开始发生了很多),但它最多应该是一行而不是   完整的堆栈跟踪。把它当作更像是也可能更好   ECONNRESET并且不记录任何内容。

     

我们目前没有公开任何有用的方法来自定义此日志记录,   但您可以在日志记录模块中自行选择。你可以附上一个   过滤到记录器并阻止exc_info [0]为SSLError的条目   例如,exc_info [1]有正确的错误代码。

我最终按照建议为Tornado的记录器添加了一个过滤器。一个轻微的障碍是record.exc_info有时是None,但在这种情况下,我能够从record.args中获取足够的信息来决定是否要过滤它。

答案 1 :(得分:0)

helgridly's own answer开始:错误can't be caught,但您可以filter日志。

  1. 创建一个检查日志记录中是否存在SSL错误的函数,并拒绝某些此类错误
  2. 将其安装为tornado.general记录器
  3. 的过滤器

    例如:

    def ssl_log_filter(record):
        if record.exc_info is not None:
            e = record.exc_info[1]
        elif len(record.args) >= 3 and isinstance(record.args[2], Exception):
            e = record.args[2]
        else:
            e = None
    
        if isinstance(e, SSLEOFError):
            return False
        if isinstance(e, SSLError):
            if e.reason in {'NO_SHARED_CIPHER'}:
                return False
    
        return True
    
    
    logging.getLogger('tornado.general').addFilter(ssl_log_filter)
    

    上面的代码仅适用于Python 3.2+。对于旧版本,请改为子类Filter