Python 3:如何从服务器端记录SSL握手错误

Python 3:如何从服务器端记录SSL握手错误,第1张

概述我正在使用HTTPServer作为使用SSL的基本HTTP服务器.我想记录客户端何时启动SSL握手(或者可能是任何时候接受套接字?)以及任何相关的错误.我想我需要扩展一些类或覆盖一些方法,但我不确定哪个或如何正确地实现它.我非常感谢任何帮助.提前致谢! 修剪示例代码: from http.server import BaseHTTPRequestHandler, HTTPServerfrom s 我正在使用httpServer作为使用SSL的基本http服务器.我想记录客户端何时启动SSL握手(或者可能是任何时候接受套接字?)以及任何相关的错误.我想我需要扩展一些类或覆盖一些方法,但我不确定哪个或如何正确地实现它.我非常感谢任何帮助.提前致谢!

修剪示例代码:

from http.server import BasehttpRequestHandler,httpServerfrom socketserver import ThreadingMixInfrom threading import Threadimport sslimport loggingimport sysclass MyhttpHandler(BasehttpRequestHandler):    def log_message(self,format,*args):        logger.info("%s - - %s" % (self.address_string(),format%args))    def do_GET(self):        self.send_response(200)        self.end_headers()        self.wfile.write('test'.encode("utf-8"))class ThreadedhttpServer(ThreadingMixIn,httpServer):    passlogger = logging.getLogger('myserver')handler = logging.fileHandler('server.log')formatter = logging.Formatter('[%(asctime)s] %(message)s')handler.setFormatter(formatter)logger.addHandler(handler)logger.setLevel(logging.DEBUG)server = ThreadedhttpServer(('',443),MyhttpHandler)server.socket = ssl.wrap_socket (server.socket,keyfile='server.key',certfile='server.crt',server_sIDe=True,cert_reqs=ssl.CERT_required,ca_certs='clIEnt.crt')Thread(target=server.serve_forever).start()try:     quitcheck = input("Type 'quit' at any time to quit.\n")    if quitcheck == "quit":        server.shutdown()except (KeyboardInterrupt) as error:    server.shutdown()
解决方法 从查看ssl模块开始,大部分相关的魔法都发生在 SSLSocket课程中.

ssl.wrap_socket()只是一个很小的便利功能,基本上可以作为SSLSocket的工厂,具有一些合理的默认值,并包装现有的套接字.

不幸的是,SSLSocket似乎没有自己的任何日志记录,因此没有简单的方法来打开日志记录级别,设置调试标志或注册任何处理程序.

所以你可以做的是继承SSLSocket,用自己的方法覆盖你感兴趣的方法做一些日志记录,并创建和使用你自己的wrap_socket辅助函数.

子类化SSLSocket

首先,将您的Python的… / lib / python2.7 / ssl.py中的ssl.wrap_socket()复制到您的代码中. (确保您复制和修改的任何代码实际上来自您正在使用的Python安装 – 代码可能在不同的Python版本之间发生了变化).

现在调整你的wrap_socket()副本

>创建一个LoggingSSLSocket实例(我们将在下面实现)而不是SSLSocket
>并在必要时使用ssl模块中的常量(本例中为ssl.CERT_NONE和ssl.PROTOCol_SSLv23)

def wrap_socket(sock,keyfile=None,certfile=None,server_sIDe=False,cert_reqs=ssl.CERT_NONE,ssl_version=ssl.PROTOCol_SSLv23,ca_certs=None,do_handshake_on_connect=True,suppress_ragged_eofs=True,ciphers=None):    return LoggingSSLSocket(sock=sock,keyfile=keyfile,certfile=certfile,server_sIDe=server_sIDe,cert_reqs=cert_reqs,ssl_version=ssl_version,ca_certs=ca_certs,do_handshake_on_connect=do_handshake_on_connect,suppress_ragged_eofs=suppress_ragged_eofs,ciphers=ciphers)

现在改变你的路线

server.socket = ssl.wrap_socket (server.socket,...)

server.socket = wrap_socket(server.socket,...)

为了使用你自己的wrap_socket().

现在为子类化SSLSocket.通过在代码中添加以下内容,创建一个LoggingSSLSocket类,该类是SSLSocket的子类:

class LoggingSSLSocket(ssl.SSLSocket):    def accept(self,*args,**kwargs):        logger.deBUG('Accepting connection...')        result = super(LoggingSSLSocket,self).accept(*args,**kwargs)        logger.deBUG('Done accepting connection.')        return result    def do_handshake(self,**kwargs):        logger.deBUG('Starting handshake...')        result = super(LoggingSSLSocket,self).do_handshake(*args,**kwargs)        logger.deBUG('Done with handshake.')        return result

这里我们重写ssl.SSLSocket的accept()do_handshake()方法 – 其他一切都保持不变,因为该类继承自SSLSocket.

覆盖方法的通用方法

我使用特定模式来覆盖这些方法,以便更容易应用于您将覆盖的几乎任何方法:

def methodname(self,**kwargs):

* args,** kwargs确保我们的方法接受任意数量的位置和关键字参数(如果有的话). accept实际上没有采取任何这些,但它仍然有效,因为Python的packing / unpacking of argument lists.

logger.deBUG('Before call to superclass method')

在调用超类方法之前,你有机会做自己的事情.

result = super(LoggingSSLSocket,self).methodname(*args,**kwargs)

这是对超类’方法的实际调用.有关其工作原理的详细信息,请参阅docs on super(),但它基本上在LoggingSSLSocket的超类(SSLSocket)上调用.methodname().因为我们将* args,** kwargs传递给方法,所以我们只传递我们的方法获得的任何位置和关键字参数 – 我们甚至不需要知道它们是什么,方法签名将始终匹配.

因为某些方法(如accept())将返回一个结果,我们存储该结果并在我们的方法结束时返回它,就在我们的调用后工作之前:

logger.deBUG('After call.')        return result

记录更多细节

如果要在日志记录语句中包含更多信息,则可能必须完全覆盖相应的方法.因此,将它们复制并根据需要进行修改,并确保满足任何缺少的导入.

以下是accept()的示例,其中包括尝试连接的客户端的IP地址和本地端口:

def accept(self):        """Accepts a new connection from a remote clIEnt,and returns        a tuple containing that new connection wrapped with a server-sIDe        SSL channel,and the address of the remote clIEnt."""        newsock,addr = socket.accept(self)        logger.deBUG("Accepting connection from '%s'..." % (addr,))        newsock = self.context.wrap_socket(newsock,do_handshake_on_connect=self.do_handshake_on_connect,suppress_ragged_eofs=self.suppress_ragged_eofs,server_sIDe=True)        logger.deBUG('Done accepting connection.')        return newsock,addr

(确保在代码顶部的导入中包含套接字导入套接字 – 请参阅ssl module’s imports以确定在获得nameError时需要从何处导入缺失的名称.配置了PyFlakes的优秀文本编辑器非常有用把那些丢失的进口指向你).

此方法将导致日志输出如下:

[2014-10-24 22:01:40,299] Accepting connection from '('127.0.0.1',64152)'...[2014-10-24 22:01:40,300] Done accepting connection.[2014-10-24 22:01:40,301] Accepting connection from '('127.0.0.1',64153)'...[2014-10-24 22:01:40,302] Done accepting connection.[2014-10-24 22:01:40,306] Accepting connection from '('127.0.0.1',64155)'...[2014-10-24 22:01:40,307] Done accepting connection.[2014-10-24 22:01:40,308] 127.0.0.1 - - "GET / http/1.1" 200 -

因为它涉及到遍布各地的相当多的变化,这里是gist containing all the changes to your example code.

总结

以上是内存溢出为你收集整理的Python 3:如何从服务器端记录SSL握手错误全部内容,希望文章能够帮你解决Python 3:如何从服务器端记录SSL握手错误所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1193223.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存