Как установить SNI через http.client.HTTPSConnection - PullRequest
0 голосов
/ 17 апреля 2020

Я использую http.client.HTTPSConnection для создания HTTPS-соединения с моим сервером. Я не могу использовать исходное имя хоста для подключения к серверу, так как это тестовая настройка, но мне нужно сделать правильное рукопожатие TLS с правильным именем хоста как SNI. Как установить SNI для приветствия клиента HTTPS-соединения?

Судя по ssl.SSLSocket.server_hostname , если бы я мог получить доступ к базовому сокету, я должен иметь возможность установить имя_сервера на это значение, которое я хочу. У HTTPSConnection действительно есть sock член, но это None после построения.

Если больше контекста исходного кода полезно, я работаю над тестовым прокси в proxy- испытатель . См. proxy_http1.py # L94

1 Ответ

0 голосов
/ 18 апреля 2020

В разделе комментариев вопроса Стеффен Ульрих направил меня к ответу. Нет прямой поддержки тому, что я пытаюсь сделать через http.client.HTTPSConnection. Однако http.client.HTTPSConnection вызывает переданную функцию ssl.SSLContext.wrap_socket из переданного SSLContext. Поэтому я смог получить то, что хотел, создав оболочку для этого класса. В случае, если это будет полезно для кого-то другого, мой код теперь выглядит следующим образом:

if scheme == 'https':
    if socket.client_sni:


        class WrapSSSLContext(ssl.SSLContext):
            '''
            HTTPSConnection provides no way to specify the
            server_hostname in the underlying socket. We
            accomplish this by wrapping the context to
            overrride the wrap_socket behavior (called later
            by HTTPSConnection) to specify the
            server_hostname that we want.
            '''
            def __new__(cls, server_hostname, *args, **kwargs):
                return super().__new__(cls, *args, *kwargs)


            def __init__(self, server_hostname, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self._server_hostname = server_hostname


            def wrap_socket(self, sock, *args, **kwargs):
                kwargs['server_hostname'] = self._server_hostname
                return super().wrap_socket(sock, *args, **kwargs)


        proxy_to_server_context = WrapSSSLContext(socket.client_sni)
    else:
        proxy_to_server_context = ssl.SSLContext()
    self.tls.conns[origin] = http.client.HTTPSConnection(
            replay_server, timeout=self.timeout,
            context=proxy_to_server_context, cert_file=self.cert_file)

Таким образом, если я хочу указать SNI, я использую пользовательский класс WrapSSSLContext, который явно предоставляет имя сервера_хоста, которое я хочу. В противном случае я просто использую стандарт ssl.SSLContext. Я подтвердил в захвате пакета, это указывает SNI, который я хочу в клиенте привет.

Спасибо Steffen!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...