我已经实现了SSL通信,客户端应用程序使用flask验证SSL服务器应用程序的身份。现在我希望SSL服务器应用程序验证SSL客户端应用程序的身份。烧瓶有可能吗?如何验证客户端证书?在第一次握手期间,客户端正在发送CSR,作为响应,我将发回由自签名CA证书签名的证书。
但我还不清楚在下次通信时服务器将如何验证客户端。是否有任何回调证书验证。 Google groups上的链接表示无法在Flask上进行ssl身份验证。为了做到这一点,需要使用像apache,ngnix这样的webserver。这是验证客户端的唯一方法吗?
还有一件事我想要实现,我需要根据他们的证书识别每个客户。甚至可以用烧瓶。
我的问题可能很天真,因为我对烧瓶还不是很熟悉
答案 0 :(得分:9)
<强>声明强>
在开始之前,我会注意到@Emanuel Ey的评论。如果首先在生产或开发服务器上完成,您可能需要考虑。例如;如果您使用的是Apache WebServer,则可以从Apache完成HTTPS组件。您唯一不同的做法是将证书详细信息作为选项传递,然后您的服务器应用程序将验证应用程序本身内的序列号。
可能
但它的可行方式并不算是良好的编程习惯。不幸的是,它无法从flask.request
访问,而且无法使用Flask包。但是,Flask使用Werkzeug,可以通过修补werkzeug.serving
包来编写主要的Flask代码。建议不要这样做,因为您可能希望稍后更新Flask或Werkzeug,您的补丁可能会中断并需要重新计算。即从0.9到1.0。
这提供了一种不使用Web服务器的解决方案。但我会推荐Web服务器/环境变量组合。这是更清洁和相对较好的做法。
我做了一些测试,看看这是否易于实现。我能够确认这个方法可以使用最新的开发代码库'Werkzeug-0.10_devdev_20141223-py2.7'。
您可能想要验证每个证书中找到的序列号(种子编号)(甚至可能还有其他一些变量)。您可能知道,序列对每个证书都是唯一的,并且在您在服务器端的证书生成过程中确定。它有助于将其与客户端记录和证书信息(如果适用)一起存储,以便稍后验证客户端证书序列号。注意:可能需要在十进制和十进制十进制之间进行更改。
Werkzeug dev_2014122
我所做的是在werkzeug.serving.BaseWSGIServer.__init__
wrap_socket()
来电中添加以下选项。
使用这些;
server_side=True, ca_certs= '/etc/apache2/ssl/ca.pem', cert_reqs=ssl.CERT_REQUIRED
注意:如果客户端证书未通过初始验证,您将无法获取客户端证书。它将是None。
然后在我的Flask测试课中,我修补了verify_request
其中
def verify_request(self, request, client_address):
cert = request.getpeercert(True)
raw = decoder.decode(cert)[0]
print "Serial Number of your certificate is: % " % str(raw[0][1])
# todo: do checks & if serial no is ok then return true
return True
werkzeug.serving.BaseWSGIServer.verify_request = verify_request
这证明了这是可能的,但您可能想要调查BaseWSGIServer继承的HTTPServer类的请求处理程序,以找到更好的方法来进行回调或覆盖。
Werkzeug 0.9.X
如果您使用的是Werkzeug 0.9.X我假设您使用的是导入from OpenSSL import SSL
。请参阅代码段here。我没有测试过这个。
您可能对此版本感兴趣的一些电话会是:
- Context.set_verify(mode, callback)
- Connection.get_peer_certificate()
<强>澄清强>
我不明白的是您在第一次握手期间发送CSR的提法。如果这是您生成客户端证书的过程,您可能需要重新考虑如何在系统和环境的上下文中执行此操作。如果我可以获得更多信息,我可以进一步评论..
此外,SSL / TLS上下文中的“握手”通常是指使用现有证书首先创建安全连接的操作。在握手之后,松散地说,建立了连接。