- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试从客户端对服务器进行 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)
客户端
我有一个 Flask 应用程序,我需要从中对上述服务器进行 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 routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
此错误是预期的,因为客户端不知道该证书。如果我跳过证书验证 (verify=False
),一切都运行良好。
如何让客户端信任这个未知的服务器 SSL 证书?我已经看到需要在客户端使用 Nginx 的解决方案。我们不能对 flask (客户端)本身做一些改变以使其信任我的服务器吗?如果是,我应该在 Flask 中做出什么确切的改变?此外,建议 urllib
是否优于 requests
。
更新 1
我这里还有一个问题。从上面,我了解到 requests.get
每次我们进行 REST 调用时都会验证证书(如果我错了请纠正我)。但是,这看起来像是一个额外的负担。难道不能一开始就建立一个加密连接,用私钥加密交换数据吗?那么,如何实现开始部分 - 通过使用公钥加密私钥发送到服务器,然后通过使用私钥加密数据开始交换数据。
最佳答案
OC (original comment):
Server Side
I am using Flask as web server. I have generated the certificate(cert.pem) and public key(key.pem) using the following command.
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
可以称为公共(public)证书,而 key.pem
实际上是您的私钥(保持安全和私密)。傅立叶。
OC (original comment):
This error is expected as the certificate is not known to the client. Everything is working perfectly fine if I skip the certificate verification (verify=False).
How do I make the client trust this unknown server SSL certificate? I have seen solutions where I need to use Nginx on the client side. Can we not do some changes on flask(client side) itself to make it trust my server? If yes, what is that exact change I should be making in Flask? Also, suggest if urllib is better than requests.
我会倒过来回答这个问题,但首先要了解一些背景知识。我发现这些链接对于理解 SSL/TLS 握手如何发生以及身份验证如何进行非常有用 - 在高层次上
现在,回到你的问题,
requests
> urllib
(个人观点,但是requests
确实有很好的支持并且很成熟——并不意味着urllib
不是)
您似乎想仅进行服务器身份验证,因为您的客户端需要服务器的公共(public)证书。来自 How SSL and TLS provide authentication :
The certificates required are as follows, where CA X issues the certificate to the SSL or TLS client, and CA Y issues the certificate to the SSL or TLS server:
For server authentication only, the SSL or TLS server needs:
The personal certificate issued to the server by CA Y
The server's private key
and the SSL or TLS client needs:
- The CA certificate for CA Y
requests.get
中使用它引用 this from requests
,它说,You can pass verify the path to a CA_BUNDLE file or directory with certificates of trusted CAs:
requests.get('https://github.com', verify='/path/to/certfile')
一旦您这样做并获得了良好的证书,它就应该可以工作。
注意:OC 中的 openssl
命令不显示 key /证书对的任何主题,这仍然会导致证书验证失败,请参阅说明如何执行的文档生成自签名证书。有提供 SAN (SubjectAltNames) 的要求,因此仅在主题中提供 CommonName (CN) 不会在未来证明您的过程。
编辑:IBM 文档中关于 CA 的说法可能令人困惑,但由于这是一个自签名证书,您不必担心这一点,只需将其视为您的 Flask 服务器就是 SSL/TLS 服务器,而任何客户端该服务器可以使用服务器的公钥进行服务器验证。
OC (original comment):
From above, I understood that requests.get verifies the certificate every time we make a REST call (Please correct me if I am wrong). But, this looks like an extra load.
没错。每次都会进行验证。为避免这种情况,您可以使用 requests
SSL Cert Verification 中提到的 requests.Session()
OC (original comment):
Can we not have an encrypted connected established in the beginning and exchange the data by encrypting it with a private key? So, how to implement the beginning part - Send private key by encrypting it with the public key to the server and then start exchanging data by encrypting the data with the private key.
这在列出的 IBM 文档中有很好的解释
关于rest - 如何让客户端接受服务器的SSL证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49008440/
我是一名优秀的程序员,十分优秀!