如何使客户端接受服务器 SSL 证书



我正在尝试从客户端对服务器进行REST调用。

服务器端

我正在使用Flask作为网络服务器。我使用以下命令生成了证书(cert.pem) 和公钥(key.pem)。

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365

以下是服务器端代码。

from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
@app.route('/someroute/<arg1>,<arg2>', methods=['GET'])
def fn1(arg1,arg2):
res = fn2(arg1, arg2)
return str(res)
def fn2(un,pwd):
#Do something and return a number
return num
if __name__ == '__main__':
context = ('cert.pem', 'key.pem')
app.run(host="ip", port=port1, debug=True, ssl_context=context)

客户端

我有一个烧瓶应用程序,我需要从中对上述服务器进行 REST 调用。以下是我用来执行此操作的代码。

import requests
# Below is the part of a function which gets called upon hitting a route in Flask.
ret = requests.get("https://<ip>:<port1>/<someroute>/arg1,arg2", verify=True)
print ret.text

这将引发以下错误。

requests.exceptions.SSLError: [Errno 1] _ssl.c:510: error:14090086:SSL 例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败

由于客户端不知道证书,因此会出现此错误。如果我跳过证书验证(verify=False),一切正常。

如何使客户端信任此未知服务器 SSL 证书?我已经看到了需要在客户端使用Nginx的解决方案。我们不能对 flask(客户端)本身进行一些更改以使其信任我的服务器吗?如果是,我应该在 Flask 中进行哪些确切更改?另外,建议urllib是否比requests好。

更新 1

我在这里还有另一个疑问。从上面,我了解到每次我们进行 REST 调用时requests.get都会验证证书(如果我错了,请纠正我)。但是,这看起来像是一个额外的负载。我们是否可以在开始时建立加密连接并通过使用私钥加密来交换数据?那么,如何实现开始部分 - 通过使用公钥加密来发送私钥到服务器,然后通过使用私钥加密数据来开始交换数据。

OC(

原始评论):

服务器端

我正在使用Flask作为网络服务器。我已经使用以下命令生成了证书(cert.pem)和公钥(key.pem)。

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 36

如果你读man req它说,

-out filename
This specifies the output filename to write to or standard output by default.
-keyout filename
This gives the filename to write the newly created private key to.  If this option is not specified then the filename present in the configuration file is used.

在这里,cert.pem可以称为公共证书,key.pem实际上是您的私钥(保持安全和私密)。FTFY。


OC(原始评论):

由于客户端不知道证书,因此会出现此错误。如果我跳过证书验证(验证=假),一切正常。

如何使客户端信任此未知服务器 SSL 证书?我已经看到了需要在客户端使用Nginx的解决方案。我们不能对 flask(客户端)本身进行一些更改以使其信任我的服务器吗?如果是,我应该在 Flask 中进行哪些确切更改?另外,建议 urllib 是否比请求更好。

我会倒着回答这个问题,但首先要介绍一点背景。我发现这些链接对于理解 - 在高层次上 - SSL/TLS握手如何发生以及如何执行身份验证非常有用

  • IBM:SSL 或 TLS 握手概述
  • IBM:SSL 和 TLS 如何提供身份验证

现在,回到你的问题,

  • requests>urllib(个人观点,但requests确实有很好的支持并且很成熟 - 并不意味着urllib不是)

  • 看起来您只想执行服务器身份验证,因为您的客户端需要服务器的公共证书。从 SSL 和 TLS 如何提供身份验证:

所需的证书如下所示,其中 CA X 向 SSL 或 TLS 客户端颁发证书,CA Y 向 SSL 或 TLS 服务器颁发证书:

仅对于服务器身份验证,SSL 或 TLS 服务器需要:

  • CA Y 颁发给服务器的个人证书

  • 服务器的私钥

以及 SSL 或 TLS 客户端需要:

CA
  • Y 的 CA 证书
  • 使用它requests.get引用来自requests,它说,

您可以使用受信任 CA 的证书验证CA_BUNDLE文件或目录的路径:

requests.get('https://github.com', verify='/path/to/certfile')

一旦你这样做并拥有良好的证书,它应该可以工作。

注意:OC 中的openssl命令不显示密钥/证书对的任何主题,这仍然无法通过证书验证,请参阅显示如何生成自签名证书的文档。需要提供 SAN(主题AltNames),因此在主题中仅提供公用名 (CN) 不会证明您的流程将来会得到证明。

编辑:IBM文档中的CA讨论可能会令人困惑,但由于这是一个自签名证书,您不必担心这一点,只需将其视为您的Flask服务器是SSL/TLS服务器,并且该服务器的任何客户端都可以使用服务器的公钥进行服务器验证。


OC(原始评论):

从上面,我了解到 requests.get 每次我们进行 REST 调用时都会验证证书(如果我错了,请纠正我)。但是,这看起来像是一个额外的负载。

这是真的。它每次都会执行验证。为避免这种情况,您可以使用requestsSSL 证书验证中所述的requests.Session()


OC(原始评论):

我们是否可以在开始时建立加密连接并通过使用私钥加密来交换数据?那么,如何实现开始部分 - 通过使用公钥加密来发送私钥到服务器,然后通过使用私钥加密数据来开始交换数据。

这在列出的 IBM 文档中得到了很好的解释

最新更新