aiohttp 和客户端 SSL 证书 [英] aiohttp and client-side SSL certificates

查看:66
本文介绍了aiohttp 和客户端 SSL 证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近从 flask + requests 转移到 aiohttp 及其异步 http 客户端.

I recently moved off from flask + requests onto aiohttp and its async http client.

在我的场景中,我需要通过 HTTPS(使用自定义证书)调用 API 并同时发送客户端证书.

In my scenario, I need to make a call to an API over HTTPS (with custom certificates) AND send a client-side certificate along.

对于第一部分(验证自定义证书),支持很明确在文档中清楚地记录了,而且效果很好.

For the first part (validating custom certs), the support is clear clearly documented int the docs and it works great.

另一方面,对于第二部分,我似乎无法找到一种简单的方法来附加自定义 SSL 客户端证书来授权客户端.

On the other hand, for the second part, I can't seem to be able to find an easy way of attaching a custom SSL client-side certificate to authorise the client.

你们知道怎么做吗?非常感谢!

Do you guys know how to do that ? Many thanks !

推荐答案

EDIT: 我已经提交了一个 PR 更新了有关该主题的 aiohttp 文档,并且已合并.

EDIT: I've submitted a PR with an update to the aiohttp documentation regarding the subject, and it's been merged.

对于将来可能遇到此问题的任何人..

For anyone who might encounter this issue in the future..

TL:DR

import ssl
import aiohttp    

ssl_ctx = ssl.create_default_context(cafile='/path_to_client_root_ca')
ssl_ctx.load_cert_chain('/path_to_client_public_key.pem', '/path_to_client_private_key.pem')

conn = aiohttp.TCPConnector(ssl_context=ssl_ctx)
session = aiohttp.ClientSession(connector=conn)

# session will now send client certificates..

长话短说 - 我查看了它是如何在请求中实现的(它巧妙地记录了 API here),显然它是在 urllib3 内部实现的.

The long story - I've looked how it's implemented in requests (which neatly documents the API here), and apparently it's implemented inside of urllib3.

urllib3 将 cert 参数一直向下传递到它的 HTTPSConnection 对象,它最终在此调用此函数:

urllib3 trickles down the cert parameter all the way down to its HTTPSConnection object, where it eventually calls this function:

...
self.sock = ssl_wrap_socket(
    sock=conn,
    keyfile=self.key_file,
    certfile=self.cert_file,
    ssl_context=self.ssl_context,
)
...

这样做:

...
if ca_certs or ca_cert_dir:
    try:
        context.load_verify_locations(ca_certs, ca_cert_dir)
    except IOError as e:  # Platform-specific: Python 2.6, 2.7, 3.2
        raise SSLError(e)
    # Py33 raises FileNotFoundError which subclasses OSError
    # These are not equivalent unless we check the errno attribute
    except OSError as e:  # Platform-specific: Python 3.3 and beyond
        if e.errno == errno.ENOENT:
            raise SSLError(e)
        raise
elif getattr(context, 'load_default_certs', None) is not None:
    # try to load OS default certs; works well on Windows (require Python3.4+)
    context.load_default_certs()

if certfile:
    context.load_cert_chain(certfile, keyfile)
if HAS_SNI:  # Platform-specific: OpenSSL with enabled SNI
    return context.wrap_socket(sock, server_hostname=server_hostname)
...

这里有趣的调用是对 load_cert_chain - 这意味着如果我们只是创建一个 ssl.SSLContext(这是一个标准库接口)对象并调用 load_cert_chain 与我们的客户端证书类似,aiohttp 的行为与 requests\urllib3 相同.

The interesting call here is to load_cert_chain - this means that if we just create an ssl.SSLContext (which is a standard library interface) object and call load_cert_chain with our client certificates like so, aiohttp will behave the same as requests\urllib3.

因此,尽管 aiohttp 的文档没有告诉您这一点,但它们确实指定您可以加载自己的 ssl.SSLContext.

So although aiohttp's documentation is lacking in telling you that, they do specify that you can load your own ssl.SSLContext.

这篇关于aiohttp 和客户端 SSL 证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆