Документация Python неофициальный перевод

ssl.md

744 строк · 70.1 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.2/library/ssl.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 17.3. [`ssl`](https://python-all.ru/3.2/library/ssl.html#module-ssl) – обёртка TLS/SSL для объектов сокетов89**Исходный код:** [Lib/ssl.py](https://python-all.ru/src/3.2/Lib/ssl.py)1011---1213Этот модуль предоставляет доступ к шифрованию и аутентификации одноранговых узлов с помощью протокола Transport Layer Security (часто называемого «Secure Sockets Layer») для сетевых сокетов, как на стороне клиента, так и на стороне сервера. В этом модуле используется библиотека OpenSSL. Он доступен на всех современных Unix-системах, Windows, Mac OS X и, вероятно, на других платформах, если на них установлен OpenSSL.1415> **Примечание**16>17> Некоторое поведение может зависеть от платформы, поскольку вызовы выполняются к API сокетов операционной системы. Установленная версия OpenSSL также может вызывать различия в поведении.1819> **Предупреждение**20>21> Внутренний генератор случайных чисел OpenSSL некорректно обрабатывает fork. Приложения должны изменять состояние PRNG родительского процесса, если они используют любую функцию SSL с помощью [`os.fork()`](https://python-all.ru/3.2/library/os.html#os.fork). Любой успешный вызов [`RAND_add()`](https://python-all.ru/3.2/library/ssl.html#ssl.RAND_add), `RAND_bytes()` или `RAND_pseudo_bytes()` является достаточным.2223В этом разделе описываются объекты и функции модуля `ssl`; за более общей информацией о TLS, SSL и сертификатах обращайтесь к документам в разделе «См. также» внизу.2425Этот модуль предоставляет класс `ssl.SSLSocket`, который является производным от типа [`socket.socket`](https://python-all.ru/3.2/library/socket.html#socket.socket) и предоставляет подобную сокету обёртку, которая также шифрует и дешифрует данные, передаваемые через сокет с помощью SSL. Он поддерживает дополнительные методы, такие как `getpeercert()`, который извлекает сертификат другой стороны соединения, и `cipher()`, который извлекает шифр, используемый для защищённого соединения.2627Для более сложных приложений класс [`ssl.SSLContext`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext) помогает управлять настройками и сертификатами, которые затем могут наследоваться SSL-сокетами, созданными через метод [`SSLContext.wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.wrap_socket).2829## 17.3.1. Функции, константы и исключения3031#### `exception ssl.SSLError`3233Возбуждается для сигнализации об ошибке базовой реализации SSL (в настоящее время предоставляемой библиотекой OpenSSL). Это указывает на некоторую проблему в вышележащем уровне шифрования и аутентификации, который накладывается на базовое сетевое соединение. Это исключение является подтипом [`socket.error`](https://python-all.ru/3.2/library/socket.html#socket.error), который в свою очередь является подтипом [`IOError`](https://python-all.ru/3.2/library/exceptions.html#IOError). Код и сообщение об ошибке экземпляров [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError) предоставляются библиотекой OpenSSL.3435#### `exception ssl.CertificateError`3637Возникает для сигнализации об ошибке с сертификатом (например, несовпадение имени хоста). Однако ошибки сертификата, обнаруженные OpenSSL, возбуждают [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError).3839### 17.3.1.1. Создание сокета4041Следующая функция позволяет создать сокет независимо. Начиная с Python 3.2, может быть более гибким использование [`SSLContext.wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.wrap_socket) вместо этого.4243#### `ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)`4445Принимает экземпляр `sock` класса [`socket.socket`](https://python-all.ru/3.2/library/socket.html#socket.socket) и возвращает экземпляр `ssl.SSLSocket`, подтип [`socket.socket`](https://python-all.ru/3.2/library/socket.html#socket.socket), который оборачивает базовый сокет в контекст SSL. Для клиентских сокетов построение контекста является отложенным; если базовый сокет ещё не подключён, построение контекста будет выполнено после вызова `connect()` на сокете. Для серверных сокетов, если у сокета нет удалённого узла, он считается слушающим сокетом, и серверная SSL-обёртка автоматически выполняется для клиентских подключений, принятых через метод `accept()`. [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket) может возбудить [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError).4647Параметры `keyfile` и `certfile` задают необязательные файлы, содержащие сертификат, используемый для идентификации локальной стороны соединения. См. обсуждение [*Certificates*](https://python-all.ru/3.2/library/ssl.html#ssl-certificates) для получения дополнительной информации о том, как сертификат хранится в `certfile`.4849Параметр `server_side` – это логическое значение, которое определяет, требуется ли от этого сокета поведение серверной или клиентской стороны.5051Параметр `cert_reqs` задаёт, требуется ли сертификат от другой стороны соединения и будет ли он проверен, если предоставлен. Он должен быть одним из трёх значений: [`CERT_NONE`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_NONE) (сертификаты игнорируются), [`CERT_OPTIONAL`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_OPTIONAL) (не требуется, но проверяется, если предоставлен) или [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED) (требуется и проверяется). Если значение этого параметра не [`CERT_NONE`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_NONE), то параметр `ca_certs` должен указывать на файл с сертификатами ЦС.5253Файл `ca_certs` содержит набор объединённых сертификатов «центров сертификации», которые используются для проверки сертификатов, переданных с другого конца соединения. См. обсуждение [*Certificates*](https://python-all.ru/3.2/library/ssl.html#ssl-certificates) для получения дополнительной информации о том, как организовать сертификаты в этом файле.5455Параметр `ssl_version` определяет, какую версию протокола SSL использовать. Обычно сервер выбирает конкретную версию протокола, а клиент должен подстраиваться под выбор сервера. Большинство версий несовместимы друг с другом. Если параметр не задан, по умолчанию используется [`PROTOCOL_SSLv23`](https://python-all.ru/3.2/library/ssl.html#ssl.PROTOCOL_SSLv23); он обеспечивает наилучшую совместимость с другими версиями.5657Ниже приведена таблица, показывающая, какие версии на стороне клиента (по вертикали) могут подключаться к каким версиям на стороне сервера (по горизонтали):5859> | *клиент* / **сервер** | **SSLv2** | **SSLv3** | **SSLv23** | **TLSv1** |60> | --- | --- | --- | --- | --- |61> | *SSLv2* | да | нет | да | нет |62> | *SSLv3* | нет | да | да | нет |63> | *SSLv23* | да | нет | да | нет |64> | *TLSv1* | нет | нет | да | да |6566> **Примечание**67>68> Какие соединения будут успешными, зависит от версии OpenSSL. Например, в некоторых старых версиях OpenSSL (таких как 0.9.7l на OS X 10.4) клиент SSLv2 не мог подключиться к серверу SSLv23. Другой пример: начиная с OpenSSL 1.0.0, клиент SSLv23 не будет фактически пытаться устанавливать SSLv2-соединения, если только явно не включить SSLv2-шифры; для этого можно указать `"ALL"` или `"SSLv2"` в качестве параметра *ciphers*.6970Параметр *ciphers* задаёт доступные шифры для этого объекта SSL. Он должен быть строкой в [формате списка шифров OpenSSL](https://python-all.ru/3.2/library/ssl.html).7172Параметр `do_handshake_on_connect` определяет, выполнять ли квитирование SSL автоматически после вызова `socket.connect()`, или же программа должна вызывать его явно с помощью метода [`SSLSocket.do_handshake()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLSocket.do_handshake). Явный вызов [`SSLSocket.do_handshake()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLSocket.do_handshake) даёт программе контроль над блокирующим поведением операций ввода-вывода сокета, участвующих в квитировании.7374Параметр `suppress_ragged_eofs` определяет, как метод `SSLSocket.recv()` должен сигнализировать о неожиданном конце файла (EOF) с другого конца соединения. Если указано значение [`True`](https://python-all.ru/3.2/library/constants.html#True) (по умолчанию), он возвращает обычный EOF (пустой объект bytes) в ответ на ошибки неожиданного EOF, возникающие в базовом сокете; если [`False`](https://python-all.ru/3.2/library/constants.html#False), он будет пробрасывать исключения обратно вызывающему коду.7576Изменено в версии 3.2: Новый необязательный аргумент *ciphers*.7778### 17.3.1.2. Генерация случайных чисел7980#### `ssl.RAND_status()`8182Возвращает True, если SSL-генератор псевдослучайных чисел был инициализирован «достаточным» количеством случайности, и False в противном случае. Для увеличения случайности генератора псевдослучайных чисел можно использовать [`ssl.RAND_egd()`](https://python-all.ru/3.2/library/ssl.html#ssl.RAND_egd) и [`ssl.RAND_add()`](https://python-all.ru/3.2/library/ssl.html#ssl.RAND_add).8384#### `ssl.RAND_egd(path)`8586Если где-то запущен демон сбора энтропии (EGD) и `path` является именем пути сокетного соединения, открытого к нему, то эта функция прочитает 256 байт случайности из сокета и добавит их в SSL-генератор псевдослучайных чисел для повышения безопасности генерируемых секретных ключей. Обычно это необходимо только в системах без лучших источников случайности.8788См. [http://egd.sourceforge.net/](https://python-all.ru/3.2/library/ssl.html) или [http://prngd.sourceforge.net/](https://python-all.ru/3.2/library/ssl.html) для получения исходных текстов демонов сбора энтропии.8990#### `ssl.RAND_add(bytes, entropy)`9192Смешивает заданные `bytes` с SSL-генератором псевдослучайных чисел. Параметр `entropy` (число с плавающей запятой) является нижней границей энтропии, содержащейся в строке (поэтому всегда можно использовать `0.0`). См. [**RFC 1750**](https://python-all.ru/3.2/library/ssl.html) для получения дополнительной информации об источниках энтропии.9394### 17.3.1.3. Обработка сертификатов9596#### `ssl.match_hostname(cert, hostname)`9798Проверяет, что *cert* (в декодированном формате, возвращаемом функцией [`SSLSocket.getpeercert()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLSocket.getpeercert)) соответствует заданному *hostname*. Применяемые правила – это правила проверки идентичности HTTPS-серверов, описанные в [**RFC 2818**](https://python-all.ru/3.2/library/ssl.html), за исключением того, что IP-адреса в настоящее время не поддерживаются. Помимо HTTPS, эта функция должна быть подходящей для проверки идентичности серверов в различных протоколах на основе SSL, таких как FTPS, IMAPS, POPS и других.99100[`CertificateError`](https://python-all.ru/3.2/library/ssl.html#ssl.CertificateError) возбуждается при неудаче. В случае успеха функция ничего не возвращает:101102```python103>>> cert = {'subject': ((('commonName', 'example.com'),),)}104>>> ssl.match_hostname(cert, "example.com")105>>> ssl.match_hostname(cert, "example.org")106Traceback (most recent call last):107  File "<stdin>", line 1, in <module>108  File "/home/py3k/Lib/ssl.py", line 130, in match_hostname109ssl.CertificateError: hostname 'example.org' doesn't match 'example.com'110```111112Новое в версии 3.2.113114#### `ssl.cert_time_to_seconds(timestring)`115116Возвращает значение с плавающей запятой, содержащее обычное время в секундах от начала эпохи, для строки времени, представляющей дату “notBefore” или “notAfter” из сертификата.117118Вот пример:119120```python121>>> import ssl122>>> ssl.cert_time_to_seconds("May  9 00:00:00 2007 GMT")1231178694000.0124>>> import time125>>> time.ctime(ssl.cert_time_to_seconds("May  9 00:00:00 2007 GMT"))126'Wed May  9 00:00:00 2007'127```128129#### `ssl.get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None)`130131По заданному адресу `addr` SSL-защищённого сервера, в виде пары (*hostname*, *port-number*), получает сертификат сервера и возвращает его в виде строки в кодировке PEM. Если указан `ssl_version`, используется эта версия протокола SSL для попытки подключения к серверу. Если указан `ca_certs`, это должен быть файл, содержащий список корневых сертификатов, в том же формате, который используется для одноимённого параметра в [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket). Вызов попытается проверить сертификат сервера по этому набору корневых сертификатов, и завершится неудачей, если проверка не пройдёт.132133#### `ssl.DER_cert_to_PEM_cert(DER_cert_bytes)`134135Принимая сертификат в виде набора байтов в кодировке DER, возвращает версию того же сертификата в виде строки в кодировке PEM.136137#### `ssl.PEM_cert_to_DER_cert(PEM_cert_string)`138139Принимая сертификат в виде строки ASCII в формате PEM, возвращает последовательность байтов в кодировке DER для того же сертификата.140141### 17.3.1.4. Константы142143#### `ssl.CERT_NONE`144145Возможное значение для [`SSLContext.verify_mode`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.verify_mode) или параметра `cert_reqs` для [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket). В этом режиме (по умолчанию) от другой стороны сокетного соединения не требуется сертификатов. Если сертификат получен от другой стороны, никаких попыток его проверки не предпринимается.146147См. обсуждение [*соображений безопасности*](https://python-all.ru/3.2/library/ssl.html#ssl-security) ниже.148149#### `ssl.CERT_OPTIONAL`150151Возможное значение для [`SSLContext.verify_mode`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.verify_mode) или параметра `cert_reqs` для [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket). В этом режиме от другой стороны сокетного соединения не требуется сертификатов; но если они предоставлены, будет предпринята попытка проверки, и при неудаче будет возбуждено [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError).152153Использование этого параметра требует передачи корректного набора сертификатов ЦС – либо в [`SSLContext.load_verify_locations()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.load_verify_locations), либо в качестве значения параметра `ca_certs` в [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket).154155#### `ssl.CERT_REQUIRED`156157Возможное значение для [`SSLContext.verify_mode`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.verify_mode) или параметра `cert_reqs` для [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket). В этом режиме от другой стороны сокетного соединения требуются сертификаты; [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError) будет возбуждено, если сертификат не предоставлен или его проверка не пройдена.158159Использование этого параметра требует передачи корректного набора сертификатов ЦС – либо в [`SSLContext.load_verify_locations()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.load_verify_locations), либо в качестве значения параметра `ca_certs` в [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket).160161#### `ssl.PROTOCOL_SSLv2`162163Выбирает SSL версии 2 в качестве протокола шифрования канала.164165Этот протокол недоступен, если OpenSSL скомпилирован с флагом OPENSSL\_NO\_SSL2 .166167> **Предупреждение**168>169> SSL версии 2 небезопасен. Его использование крайне не рекомендуется.170171#### `ssl.PROTOCOL_SSLv23`172173Выбирает SSL версии 2 или 3 в качестве протокола шифрования канала. Это настройка для использования с серверами для максимальной совместимости с другой стороной SSL-соединения, но может привести к выбору довольно низкокачественных шифров для шифрования.174175#### `ssl.PROTOCOL_SSLv3`176177Выбирает SSL версии 3 в качестве протокола шифрования канала. Для клиентов это максимально совместимый вариант SSL.178179#### `ssl.PROTOCOL_TLSv1`180181Выбирает TLS версии 1 в качестве протокола шифрования канала. Это самая современная версия и, вероятно, лучший выбор для максимальной защиты, если обе стороны её поддерживают.182183#### `ssl.OP_ALL`184185Включает обходные решения для различных ошибок, присутствующих в других реализациях SSL. Этот параметр установлен по умолчанию. Он не обязательно устанавливает те же флаги, что и константа `SSL_OP_ALL` в OpenSSL.186187Новое в версии 3.2.188189#### `ssl.OP_NO_SSLv2`190191Запрещает соединение SSLv2. Этот параметр применим только в сочетании с [`PROTOCOL_SSLv23`](https://python-all.ru/3.2/library/ssl.html#ssl.PROTOCOL_SSLv23). Он не позволяет одноранговым узлам выбирать SSLv2 в качестве версии протокола.192193Новое в версии 3.2.194195#### `ssl.OP_NO_SSLv3`196197Запрещает соединение SSLv3. Этот параметр применим только в сочетании с [`PROTOCOL_SSLv23`](https://python-all.ru/3.2/library/ssl.html#ssl.PROTOCOL_SSLv23). Он не позволяет одноранговым узлам выбирать SSLv3 в качестве версии протокола.198199Новое в версии 3.2.200201#### `ssl.OP_NO_TLSv1`202203Запрещает соединение TLSv1. Этот параметр применим только в сочетании с [`PROTOCOL_SSLv23`](https://python-all.ru/3.2/library/ssl.html#ssl.PROTOCOL_SSLv23). Он не позволяет одноранговым узлам выбирать TLSv1 в качестве версии протокола.204205Новое в версии 3.2.206207#### `ssl.HAS_SNI`208209Определяет, имеет ли библиотека OpenSSL встроенную поддержку расширения *Server Name Indication* для протоколов SSLv3 и TLSv1 (как определено в [**RFC 4366**](https://python-all.ru/3.2/library/ssl.html)). Если истина, можно использовать аргумент *server\_hostname* с [`SSLContext.wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.wrap_socket).210211Новое в версии 3.2.212213#### `ssl.OPENSSL_VERSION`214215Строка с версией библиотеки OpenSSL, загруженной интерпретатором:216217```python218>>> ssl.OPENSSL_VERSION219'OpenSSL 0.9.8k 25 Mar 2009'220```221222Новое в версии 3.2.223224#### `ssl.OPENSSL_VERSION_INFO`225226Кортеж из пяти целых чисел, содержащий информацию о версии библиотеки OpenSSL:227228```python229>>> ssl.OPENSSL_VERSION_INFO230(0, 9, 8, 11, 15)231```232233Новое в версии 3.2.234235#### `ssl.OPENSSL_VERSION_NUMBER`236237Сырой номер версии библиотеки OpenSSL в виде целого числа:238239```python240>>> ssl.OPENSSL_VERSION_NUMBER2419470143242>>> hex(ssl.OPENSSL_VERSION_NUMBER)243'0x9080bf'244```245246Новое в версии 3.2.247248## 17.3.2. SSL-сокеты249250SSL-сокеты предоставляют следующие методы [*объектов сокетов*](https://python-all.ru/3.2/library/socket.html#socket-objects):251252- [`accept()`](https://python-all.ru/3.2/library/socket.html#socket.socket.accept)253- [`bind()`](https://python-all.ru/3.2/library/socket.html#socket.socket.bind)254- [`close()`](https://python-all.ru/3.2/library/socket.html#socket.socket.close)255- [`connect()`](https://python-all.ru/3.2/library/socket.html#socket.socket.connect)256- [`detach()`](https://python-all.ru/3.2/library/socket.html#socket.socket.detach)257- [`fileno()`](https://python-all.ru/3.2/library/socket.html#socket.socket.fileno)258- [`getpeername()`](https://python-all.ru/3.2/library/socket.html#socket.socket.getpeername), [`getsockname()`](https://python-all.ru/3.2/library/socket.html#socket.socket.getsockname)259- [`getsockopt()`](https://python-all.ru/3.2/library/socket.html#socket.socket.getsockopt), [`setsockopt()`](https://python-all.ru/3.2/library/socket.html#socket.socket.setsockopt)260- [`gettimeout()`](https://python-all.ru/3.2/library/socket.html#socket.socket.gettimeout), [`settimeout()`](https://python-all.ru/3.2/library/socket.html#socket.socket.settimeout), [`setblocking()`](https://python-all.ru/3.2/library/socket.html#socket.socket.setblocking)261- [`listen()`](https://python-all.ru/3.2/library/socket.html#socket.socket.listen)262- [`makefile()`](https://python-all.ru/3.2/library/socket.html#socket.socket.makefile)263- [`recv()`](https://python-all.ru/3.2/library/socket.html#socket.socket.recv), [`recv_into()`](https://python-all.ru/3.2/library/socket.html#socket.socket.recv_into) (но передача ненулевого аргумента `flags` не допускается)264- [`send()`](https://python-all.ru/3.2/library/socket.html#socket.socket.send), [`sendall()`](https://python-all.ru/3.2/library/socket.html#socket.socket.sendall) (с тем же ограничением)265- [`shutdown()`](https://python-all.ru/3.2/library/socket.html#socket.socket.shutdown)266267Однако, поскольку протокол SSL (и TLS) имеет собственную структуру поверх TCP, абстракция SSL-сокетов может в некоторых аспектах отличаться от спецификации обычных сокетов на уровне ОС. Особенно см. [*примечания о неблокирующих сокетах*](https://python-all.ru/3.2/library/ssl.html#ssl-nonblocking).268269SSL-сокеты также имеют следующие дополнительные методы и атрибуты:270271#### `SSLSocket.do_handshake()`272273Выполняет рукопожатие для настройки SSL.274275#### `SSLSocket.getpeercert(binary_form=False)`276277Если на другом конце соединения нет сертификата у удаленной стороны, возвращается `None`.278279Если параметр `binary_form` равен [`False`](https://python-all.ru/3.2/library/constants.html#False) и сертификат был получен от однорангового узла, этот метод возвращает экземпляр [`dict`](https://python-all.ru/3.2/library/stdtypes.html#dict). Если сертификат не был проверен, словарь будет пустым. Если сертификат был проверен, возвращается словарь с несколькими ключами, среди которых `subject` (субъект, на который был выдан сертификат) и `issuer` (эмитент, выпустивший сертификат). Если сертификат содержит экземпляр расширения *Subject Alternative Name* (см. [**RFC 3280**](https://python-all.ru/3.2/library/ssl.html)), в словаре также будет ключ `subjectAltName`.280281Поля `subject` и `issuer` являются кортежами, содержащими последовательность относительных уникальных имен (RDN), указанных в структуре данных сертификата для соответствующих полей. Каждый RDN представляет собой последовательность пар «имя-значение». Вот пример из реального мира:282283```python284{'issuer': ((('countryName', 'IL'),),285            (('organizationName', 'StartCom Ltd.'),),286            (('organizationalUnitName',287              'Secure Digital Certificate Signing'),),288            (('commonName',289              'StartCom Class 2 Primary Intermediate Server CA'),)),290 'notAfter': 'Nov 22 08:15:19 2013 GMT',291 'notBefore': 'Nov 21 03:09:52 2011 GMT',292 'serialNumber': '95F0',293 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),),294             (('countryName', 'US'),),295             (('stateOrProvinceName', 'California'),),296             (('localityName', 'San Francisco'),),297             (('organizationName', 'Electronic Frontier Foundation, Inc.'),),298             (('commonName', '*.eff.org'),),299             (('emailAddress', 'hostmaster@eff.org'),)),300 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')),301 'version': 3}302```303304> **Примечание**305>306> Для проверки сертификата для конкретной службы можно использовать функцию [`match_hostname()`](https://python-all.ru/3.2/library/ssl.html#ssl.match_hostname).307308Если параметр `binary_form` равен [`True`](https://python-all.ru/3.2/library/constants.html#True) и сертификат был предоставлен, этот метод возвращает полный сертификат в DER-кодировке в виде последовательности байтов или [`None`](https://python-all.ru/3.2/library/constants.html#None), если одноранговый узел не предоставил сертификат. Возвращаемое значение не зависит от проверки; если проверка требовалась ([`CERT_OPTIONAL`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_OPTIONAL) или [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED)), сертификат будет проверен, но если для установки соединения использовалось [`CERT_NONE`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_NONE), то сертификат (если он есть) проверен не будет.309310Изменено в версии 3.2: Возвращаемый словарь теперь содержит дополнительные элементы, такие как `issuer` и `notBefore`.311312#### `SSLSocket.cipher()`313314Возвращает кортеж из трех значений, содержащий название используемого шифра, версию протокола SSL, которая определяет его использование, и количество используемых секретных битов. Если соединение не установлено, возвращает `None`.315316#### `SSLSocket.unwrap()`317318Выполняет рукопожатие завершения SSL, которое удаляет слой TLS из базового сокета и возвращает объект базового сокета. Это можно использовать для перехода от зашифрованной работы по соединению к незашифрованной. Возвращённый сокет всегда следует использовать для дальнейшего обмена данными с другой стороной соединения, а не исходный сокет.319320#### `SSLSocket.context`321322Объект [`SSLContext`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext), к которому привязан данный SSL-сокет. Если SSL-сокет был создан с помощью функции верхнего уровня [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket) (а не [`SSLContext.wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.wrap_socket)), то это пользовательский объект контекста, созданный для данного SSL-сокета.323324Новое в версии 3.2.325326## 17.3.3. Контексты SSL327328Новое в версии 3.2.329330Контекст SSL хранит различные данные, которые живут дольше, чем отдельные SSL-соединения, такие как параметры конфигурации SSL, сертификат(ы) и закрытый(е) ключ(и). Он также управляет кешем SSL-сессий для серверных сокетов, чтобы ускорить повторные подключения от одних и тех же клиентов.331332#### `class ssl.SSLContext(protocol)`333334Создает новый SSL-контекст. Необходимо передать *протокол*, который должен быть одной из констант `PROTOCOL_*`, определенных в этом модуле. Для максимальной совместимости рекомендуется использовать [`PROTOCOL_SSLv23`](https://python-all.ru/3.2/library/ssl.html#ssl.PROTOCOL_SSLv23).335336Объекты [`SSLContext`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext) имеют следующие методы и атрибуты:337338#### `SSLContext.load_cert_chain(certfile, keyfile=None)`339340Загружает закрытый ключ и соответствующий сертификат. Строка *certfile* должна быть путём к одному файлу в формате PEM, содержащему сертификат, а также любое количество сертификатов УЦ, необходимых для подтверждения подлинности сертификата. Строка *keyfile*, если указана, должна указывать на файл, содержащий закрытый ключ. В противном случае закрытый ключ также будет взят из *certfile*. Смотрите обсуждение [*Certificates*](https://python-all.ru/3.2/library/ssl.html#ssl-certificates) для получения дополнительной информации о том, как сертификат хранится в *certfile*.341342Исключение [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError) возбуждается, если закрытый ключ не соответствует сертификату.343344#### `SSLContext.load_verify_locations(cafile=None, capath=None)`345346Загружает набор сертификатов «удостоверяющего центра» (CA), используемых для проверки сертификатов других участников, когда [`verify_mode`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.verify_mode) отличен от [`CERT_NONE`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_NONE). Должен быть указан хотя бы один из параметров *cafile* или *capath*.347348Строка *cafile*, если присутствует, содержит путь к файлу, содержащему объединённые сертификаты CA в формате PEM. См. обсуждение [*Сертификаты*](https://python-all.ru/3.2/library/ssl.html#ssl-certificates) для получения дополнительной информации о том, как организовать сертификаты в этом файле.349350Строка *capath*, если присутствует, задаёт путь к каталогу, содержащему несколько сертификатов CA в формате PEM, согласно [специфической структуре OpenSSL](https://python-all.ru/3.2/library/ssl.html).351352#### `SSLContext.set_default_verify_paths()`353354Загружает набор сертификатов по умолчанию “certification authority” (CA) из пути файловой системы, заданного при сборке библиотеки OpenSSL. К сожалению, нет простого способа узнать, успешно ли выполняется этот метод: ошибка не возвращается, если сертификаты не найдены. Однако, если библиотека OpenSSL поставляется как часть операционной системы, она, скорее всего, настроена правильно.355356#### `SSLContext.set_ciphers(ciphers)`357358Устанавливает доступные шифры для сокетов, созданных с этим контекстом. Это должна быть строка в [формате списка шифров OpenSSL](https://python-all.ru/3.2/library/ssl.html). Если ни один шифр не может быть выбран (из-за опций компиляции или других настроек, запрещающих использование всех указанных шифров), будет возбуждено исключение [`SSLError`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLError).359360> **Примечание**361>362> при подключении метод [`SSLSocket.cipher()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLSocket.cipher) SSL-сокетов вернёт текущий выбранный шифр.363364#### `SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None)`365366Оборачивает существующий сокет Python *sock* и возвращает объект `SSLSocket`. SSL-сокет привязан к контексту, его настройкам и сертификатам. Параметры *server\_side*, *do\_handshake\_on\_connect* и *suppress\_ragged\_eofs* имеют тот же смысл, что и в функции верхнего уровня [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket).367368При клиентских подключениях необязательный параметр *server\_hostname* задает имя хоста службы, к которой осуществляется подключение. Это позволяет одному серверу обслуживать несколько SSL-сервисов с разными сертификатами, по аналогии с виртуальными хостами HTTP. Указание *server\_hostname* приведет к возбуждению [`ValueError`](https://python-all.ru/3.2/library/exceptions.html#ValueError), если библиотека OpenSSL не поддерживает эту возможность (то есть если [`HAS_SNI`](https://python-all.ru/3.2/library/ssl.html#ssl.HAS_SNI) равно [`False`](https://python-all.ru/3.2/library/constants.html#False)). Указание *server\_hostname* также приведет к [`ValueError`](https://python-all.ru/3.2/library/exceptions.html#ValueError), если *server\_side* имеет значение true.369370#### `SSLContext.session_stats()`371372Получает статистику о сеансах SSL, созданных или управляемых этим контекстом. Возвращается словарь, который сопоставляет названия каждого [фрагмента информации](https://python-all.ru/3.2/library/ssl.html) с их числовыми значениями. Например, вот общее количество попаданий и промахов в кэше сеансов с момента создания контекста:373374```python375>>> stats = context.session_stats()376>>> stats['hits'], stats['misses']377(0, 0)378```379380#### `SSLContext.options`381382Целое число, представляющее набор SSL-опций, включённых в этом контексте. Значение по умолчанию – [`OP_ALL`](https://python-all.ru/3.2/library/ssl.html#ssl.OP_ALL), но можно задать другие опции, например [`OP_NO_SSLv2`](https://python-all.ru/3.2/library/ssl.html#ssl.OP_NO_SSLv2), объединяя их логическим ИЛИ.383384> **Примечание**385>386> В версиях OpenSSL старше 0.9.8m можно только устанавливать опции, но не сбрасывать их. Попытка сбросить опцию (путём сброса соответствующих битов) вызовет `ValueError`.387388#### `SSLContext.protocol`389390Версия протокола, выбранная при создании контекста. Этот атрибут доступен только для чтения.391392#### `SSLContext.verify_mode`393394Определяет, следует ли пытаться проверять сертификаты других одноранговых узлов и как себя вести при неудачной проверке. Этот атрибут должен быть одним из [`CERT_NONE`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_NONE), [`CERT_OPTIONAL`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_OPTIONAL) или [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED).395396## 17.3.4. Сертификаты397398Сертификаты в целом являются частью системы открытых и закрытых ключей. В этой системе каждому *субъекту* (которым может быть машина, человек или организация) присваивается уникальный двухчастный ключ шифрования. Одна часть ключа является открытой и называется *открытым ключом*; другая часть хранится в секрете и называется *закрытым ключом*. Две части связаны так, что если зашифровать сообщение одной частью, его можно расшифровать только другой частью, и **только** другой частью.399400Сертификат содержит информацию о двух субъектах. Он содержит имя *субъекта* и его открытый ключ. Также он содержит утверждение второго субъекта, *издателя*, о том, что субъект является тем, за кого себя выдаёт, и что это действительно открытый ключ субъекта. Утверждение издателя подписано закрытым ключом издателя, который известен только издателю. Однако любой может проверить утверждение издателя, найдя его открытый ключ, расшифровав им утверждение и сравнив его с другой информацией в сертификате. Сертификат также содержит информацию о периоде времени, в течение которого он действителен. Это выражается двумя полями, называемыми «notBefore» и «notAfter».401402При использовании сертификатов в Python клиент или сервер может использовать сертификат для подтверждения своей личности. Другая сторона сетевого соединения также может быть обязана предоставить сертификат, и этот сертификат может быть проверен к удовлетворению клиента или сервера, требующего такой проверки. Можно настроить попытку соединения так, чтобы она вызывала исключение, если проверка не удалась. Проверка выполняется автоматически базовым фреймворком OpenSSL; приложению не нужно вникать в её механику. Но приложению обычно необходимо предоставить наборы сертификатов, чтобы этот процесс мог происходить.403404Python uses files to contain certificates. They should be formatted as “PEM” (see [**RFC 1422**](https://python-all.ru/3.2/library/ssl.html)), which is a base-64 encoded form wrapped with a header line and a footer line:405406```python407-----BEGIN CERTIFICATE-----408... (certificate in base64 PEM encoding) ...409-----END CERTIFICATE-----410```411412### 17.3.4.1. Цепочки сертификатов413414The Python files which contain certificates can contain a sequence of certificates, sometimes called a *certificate chain*. This chain should start with the specific certificate for the principal who “is” the client or server, and then the certificate for the issuer of that certificate, and then the certificate for the issuer of *that* certificate, and so on up the chain till you get to a certificate which is *self-signed*, that is, a certificate which has the same subject and issuer, sometimes called a *root certificate*. The certificates should just be concatenated together in the certificate file. For example, suppose we had a three certificate chain, from our server certificate to the certificate of the certification authority that signed our server certificate, to the root certificate of the agency which issued the certification authority’s certificate:415416```python417-----BEGIN CERTIFICATE-----418... (certificate for your server)...419-----END CERTIFICATE-----420-----BEGIN CERTIFICATE-----421... (the certificate for the CA)...422-----END CERTIFICATE-----423-----BEGIN CERTIFICATE-----424... (the root certificate for the CA's issuer)...425-----END CERTIFICATE-----426```427428### 17.3.4.2. Сертификаты УЦ429430Если требуется проверка сертификата другой стороны соединения, необходимо предоставить файл «CA certs», содержащий цепочки сертификатов для каждого издателя, которому вы готовы доверять. Этот файл просто содержит эти цепочки, объединённые вместе. Для проверки Python будет использовать первую подходящую цепочку в файле. Некоторые «стандартные» корневые сертификаты доступны от различных центров сертификации: [CACert.org](https://python-all.ru/3.2/library/ssl.html), [Thawte](https://python-all.ru/3.2/library/ssl.html), [Verisign](https://python-all.ru/3.2/library/ssl.html), [Positive SSL](https://python-all.ru/3.2/library/ssl.html) (используется python.org), [Equifax и GeoTrust](https://python-all.ru/3.2/library/ssl.html).431432В общем случае, если вы используете SSL3 или TLS1, не нужно помещать полную цепочку в файл «CA certs»; достаточно корневых сертификатов, а удалённый узел должен предоставить остальные сертификаты, необходимые для построения цепочки от своего сертификата до корневого. См. [**RFC 4158**](https://python-all.ru/3.2/library/ssl.html) для более подробного обсуждения способов построения цепочек сертификатов.433434### 17.3.4.3. Совмещённый ключ и сертификат435436Часто закрытый ключ хранится в том же файле, что и сертификат; в этом случае нужно передать только параметр `certfile` в [`SSLContext.load_cert_chain()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.load_cert_chain) и [`wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.wrap_socket). Если закрытый ключ хранится вместе с сертификатом, он должен располагаться перед первым сертификатом в цепочке сертификатов:437438```python439-----BEGIN RSA PRIVATE KEY-----440... (private key in base64 encoding) ...441-----END RSA PRIVATE KEY-----442-----BEGIN CERTIFICATE-----443... (certificate in base64 PEM encoding) ...444-----END CERTIFICATE-----445```446447### 17.3.4.4. Самоподписанные сертификаты448449Если планируется создать сервер, предоставляющий услуги SSL-защищённого соединения, потребуется приобрести сертификат для этой службы. Существует много способов получения подходящих сертификатов, например покупка в удостоверяющем центре. Ещё одна распространённая практика – сгенерировать самоподписанный сертификат. Самый простой способ сделать это – использовать пакет OpenSSL, примерно следующим образом:450451```python452% openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem453Generating a 1024 bit RSA private key454.......++++++455.............................++++++456writing new private key to 'cert.pem'457-----458You are about to be asked to enter information that will be incorporated459into your certificate request.460What you are about to enter is what is called a Distinguished Name or a DN.461There are quite a few fields but you can leave some blank462For some fields there will be a default value,463If you enter '.', the field will be left blank.464-----465Country Name (2 letter code) [AU]:US466State or Province Name (full name) [Some-State]:MyState467Locality Name (eg, city) []:Some City468Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc.469Organizational Unit Name (eg, section) []:My Group470Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com471Email Address []:ops@myserver.mygroup.myorganization.com472%473```474475Недостаток самоподписанного сертификата в том, что он является собственным корневым сертификатом, и никто другой не будет иметь его в своём кэше известных (и доверенных) корневых сертификатов.476477## 17.3.5. Примеры478479### 17.3.5.1. Проверка поддержки SSL480481Чтобы проверить наличие поддержки SSL в установке Python, в пользовательском коде следует использовать следующую идиому:482483```python484try:485    import ssl486except ImportError:487    pass488else:489    ... # сделать что-то, что требует поддержки SSL490```491492### 17.3.5.2. Работа на стороне клиента493494Этот пример подключается к SSL-серверу и выводит его сертификат:495496```python497import socket, ssl, pprint498499s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)500# требовать сертификат от сервера501ssl_sock = ssl.wrap_socket(s,502                           ca_certs="/etc/ca_certs_file",503                           cert_reqs=ssl.CERT_REQUIRED)504ssl_sock.connect(('www.verisign.com', 443))505506pprint.pprint(ssl_sock.getpeercert())507# закрытие SSLSocket также закроет нижележащий сокет508ssl_sock.close()509```510511По состоянию на 6 января 2012 года сертификат, выводимый этой программой, выглядит следующим образом:512513```python514{'issuer': ((('countryName', 'US'),),515            (('organizationName', 'VeriSign, Inc.'),),516            (('organizationalUnitName', 'VeriSign Trust Network'),),517            (('organizationalUnitName',518              'Terms of use at https://www.verisign.com/rpa (c)06'),),519            (('commonName',520              'VeriSign Class 3 Extended Validation SSL SGC CA'),)),521 'notAfter': 'May 25 23:59:59 2012 GMT',522 'notBefore': 'May 26 00:00:00 2010 GMT',523 'serialNumber': '53D2BEF924A7245E83CA01E46CAA2477',524 'subject': ((('1.3.6.1.4.1.311.60.2.1.3', 'US'),),525             (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),),526             (('businessCategory', 'V1.0, Clause 5.(b)'),),527             (('serialNumber', '2497886'),),528             (('countryName', 'US'),),529             (('postalCode', '94043'),),530             (('stateOrProvinceName', 'California'),),531             (('localityName', 'Mountain View'),),532             (('streetAddress', '487 East Middlefield Road'),),533             (('organizationName', 'VeriSign, Inc.'),),534             (('organizationalUnitName', ' Production Security Services'),),535             (('commonName', 'www.verisign.com'),)),536 'subjectAltName': (('DNS', 'www.verisign.com'),537                    ('DNS', 'verisign.com'),538                    ('DNS', 'www.verisign.net'),539                    ('DNS', 'verisign.net'),540                    ('DNS', 'www.verisign.mobi'),541                    ('DNS', 'verisign.mobi'),542                    ('DNS', 'www.verisign.eu'),543                    ('DNS', 'verisign.eu')),544 'version': 3}545```546547Другой пример сначала создаёт контекст SSL, указывает ему проверять сертификаты, отправляемые узлами, и передаёт ему набор известных центров сертификации (CA):548549```python550>>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)551>>> context.verify_mode = ssl.CERT_REQUIRED552>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")553```554555(предполагается, что ваша операционная система помещает набор всех сертификатов CA в `/etc/ssl/certs/ca-bundle.crt`; если нет, вы получите ошибку и придётся изменить путь)556557При использовании контекста для подключения к серверу [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED) проверяет сертификат сервера: он гарантирует, что сертификат сервера был подписан одним из сертификатов ЦС, и проверяет корректность подписи:558559```python560>>> conn = context.wrap_socket(socket.socket(socket.AF_INET))561>>> conn.connect(("linuxfr.org", 443))562```563564Затем следует получить сертификат и проверить его поля на соответствие:565566```python567>>> cert = conn.getpeercert()568>>> ssl.match_hostname(cert, "linuxfr.org")569```570571Визуальная проверка показывает, что сертификат действительно идентифицирует нужный сервис (а именно, HTTPS-хост `linuxfr.org`):572573```python574>>> pprint.pprint(cert)575{'issuer': ((('organizationName', 'CAcert Inc.'),),576            (('organizationalUnitName', 'http://www.CAcert.org'),),577            (('commonName', 'CAcert Class 3 Root'),)),578 'notAfter': 'Jun  7 21:02:24 2013 GMT',579 'notBefore': 'Jun  8 21:02:24 2011 GMT',580 'serialNumber': 'D3E9',581 'subject': ((('commonName', 'linuxfr.org'),),),582 'subjectAltName': (('DNS', 'linuxfr.org'),583                    ('othername', '<unsupported>'),584                    ('DNS', 'linuxfr.org'),585                    ('othername', '<unsupported>'),586                    ('DNS', 'dev.linuxfr.org'),587                    ('othername', '<unsupported>'),588                    ('DNS', 'prod.linuxfr.org'),589                    ('othername', '<unsupported>'),590                    ('DNS', 'alpha.linuxfr.org'),591                    ('othername', '<unsupported>'),592                    ('DNS', '*.linuxfr.org'),593                    ('othername', '<unsupported>')),594 'version': 3}595```596597Теперь, убедившись в его подлинности, можно приступать к общению с сервером:598599```python600>>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")601>>> pprint.pprint(conn.recv(1024).split(b"\r\n"))602[b'HTTP/1.1 302 Found',603 b'Date: Sun, 16 May 2010 13:43:28 GMT',604 b'Server: Apache/2.2',605 b'Location: https://linuxfr.org/pub/',606 b'Vary: Accept-Encoding',607 b'Connection: close',608 b'Content-Type: text/html; charset=iso-8859-1',609 b'',610 b'']611```612613См. обсуждение [*соображений безопасности*](https://python-all.ru/3.2/library/ssl.html#ssl-security) ниже.614615### 17.3.5.3. Работа на стороне сервера616617Для работы сервера обычно нужен сертификат сервера и закрытый ключ, каждый в отдельном файле. Сначала создаётся контекст, содержащий ключ и сертификат, чтобы клиенты могли проверить вашу подлинность. Затем открывается сокет, привязывается к порту, вызывается `listen()`, и начинается ожидание подключения клиентов:618619```python620import socket, ssl621622context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)623context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")624625bindsocket = socket.socket()626bindsocket.bind(('myaddr.mydomain.com', 10023))627bindsocket.listen(5)628```629630Когда клиент подключается, вызывается `accept()` на сокете, чтобы получить новый сокет от другой стороны, и используется метод контекста [`SSLContext.wrap_socket()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.wrap_socket) для создания серверного SSL-сокета для соединения:631632```python633while True:634    newsocket, fromaddr = bindsocket.accept()635    connstream = context.wrap_socket(newsocket, server_side=True)636    try:637        deal_with_client(connstream)638    finally:639        connstream.shutdown(socket.SHUT_RDWR)640        connstream.close()641```642643Затем считываются данные из `connstream` и выполняется с ними какая-то работа, пока не завершится взаимодействие с клиентом (или клиент с вами):644645```python646def deal_with_client(connstream):647    data = connstream.recv(1024)648    # пустые данные означают, что клиент закончил работу с нами649    while data:650        if not do_something(connstream, data):651            # будем считать, что do_something возвращает False652            # когда мы закончили с клиентом653            break654        data = connstream.recv(1024)655    # закончили с клиентом656```657658И возврат к ожиданию новых клиентских подключений (конечно, настоящий сервер, вероятно, обрабатывал бы каждое клиентское соединение в отдельном потоке или переводил сокеты в неблокирующий режим и использовал цикл событий).659660## 17.3.6. Замечания о неблокирующих сокетах661662При работе с неблокирующими сокетами необходимо учитывать несколько моментов:663664- Вызов [`select()`](https://python-all.ru/3.2/library/select.html#select.select) сообщает, что сокет на уровне ОС можно читать (или писать), но это не означает, что на верхнем уровне SSL имеется достаточно данных. Например, может прийти только часть SSL-фрейма. Поэтому необходимо быть готовым обработать ошибки `SSLSocket.recv()` и `SSLSocket.send()` и повторить попытку после очередного вызова [`select()`](https://python-all.ru/3.2/library/select.html#select.select).665666  (разумеется, аналогичные положения применимы при использовании других примитивов, таких как [`poll()`](https://python-all.ru/3.2/library/select.html#select.poll))667- Само рукопожатие SSL будет неблокирующим: метод [`SSLSocket.do_handshake()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLSocket.do_handshake) нужно повторять до успешного завершения. Вот краткий пример с использованием [`select()`](https://python-all.ru/3.2/library/select.html#select.select) для ожидания готовности сокета:668669  ```python670  while True:671      try:672          sock.do_handshake()673          break674      except ssl.SSLError as err:675          if err.args[0] == ssl.SSL_ERROR_WANT_READ:676              select.select([sock], [], [])677          elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:678              select.select([], [sock], [])679          else:680              raise681  ```682683## 17.3.7. Вопросы безопасности684685### 17.3.7.1. Проверка сертификатов686687[`CERT_NONE`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_NONE) является значением по умолчанию. Поскольку он не аутентифицирует другую сторону, это может быть небезопасно, особенно в клиентском режиме, где в большинстве случаев требуется убедиться в подлинности сервера, с которым идёт общение. Поэтому в клиентском режиме настоятельно рекомендуется использовать [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED). Однако сам по себе он недостаточен; необходимо также проверить, что сертификат сервера, который можно получить вызовом [`SSLSocket.getpeercert()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLSocket.getpeercert), соответствует нужному сервису. Для многих протоколов и приложений сервис может быть идентифицирован по имени хоста; в этом случае можно использовать функцию [`match_hostname()`](https://python-all.ru/3.2/library/ssl.html#ssl.match_hostname).688689В серверном режиме, если требуется аутентифицировать клиентов с помощью SSL-слоя (а не через механизм аутентификации более высокого уровня), также нужно указать [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED) и аналогично проверять клиентский сертификат.690691> > **Примечание**692> >693> > В клиентском режиме [`CERT_OPTIONAL`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_OPTIONAL) и [`CERT_REQUIRED`](https://python-all.ru/3.2/library/ssl.html#ssl.CERT_REQUIRED) эквивалентны, если не включены анонимные шифры (по умолчанию они отключены).694695### 17.3.7.2. Версии протоколов696697SSL версии 2 считается небезопасным, и поэтому его использование опасно. Если требуется максимальная совместимость между клиентами и серверами, рекомендуется использовать [`PROTOCOL_SSLv23`](https://python-all.ru/3.2/library/ssl.html#ssl.PROTOCOL_SSLv23) в качестве версии протокола, а затем явно отключить SSLv2 с помощью атрибута [`SSLContext.options`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.options):698699```python700context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)701context.options |= ssl.OP_NO_SSLv2702```703704Созданный выше контекст SSL будет разрешать соединения SSLv3 и TLSv1, но не SSLv2.705706### 17.3.7.3. Выбор шифров707708Если у вас повышенные требования к безопасности, точную настройку шифров, разрешённых при согласовании SSL-сеанса, можно выполнить с помощью метода [`SSLContext.set_ciphers()`](https://python-all.ru/3.2/library/ssl.html#ssl.SSLContext.set_ciphers). Начиная с Python 3.2.3, модуль ssl по умолчанию отключает некоторые слабые шифры, но можно дополнительно ограничить выбор шифров. Например:709710```python711context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)712context.set_ciphers('HIGH:!aNULL:!eNULL')713```714715Часть спецификации шифров `!aNULL:!eNULL` необходима для отключения шифров, которые не обеспечивают одновременно шифрование и аутентификацию. Обязательно прочитайте документацию OpenSSL о [формате списка шифров](https://python-all.ru/3.2/library/ssl.html). Чтобы проверить, какие шифры включены заданным списком, используйте команду `openssl ciphers` в вашей системе.716717> **См. также**718>719> **Класс [`socket.socket`](https://python-all.ru/3.2/library/socket.html#socket.socket)**720>721> Документация базового класса722>723> [`socket`](https://python-all.ru/3.2/library/socket.html#module-socket)724>725> **[TLS (безопасность транспортного уровня) и SSL (уровень защищённых сокетов)](https://python-all.ru/3.2/library/ssl.html)**726>727> Debby Koren728>729> **[RFC 1422: Улучшение конфиденциальности для интернет-электронной почты: Часть II: Управление ключами на основе сертификатов](https://python-all.ru/3.2/library/ssl.html)**730>731> Steve Kent732>733> **[RFC 1750: Рекомендации по случайности для безопасности](https://python-all.ru/3.2/library/ssl.html)**734>735> D. Eastlake et. al.736>737> **[RFC 3280: Инфраструктура открытых ключей Internet X.509 – профиль сертификатов и списков отзыва](https://python-all.ru/3.2/library/ssl.html)**738>739> Housley et. al.740>741> **[RFC 4366: Расширения безопасности транспортного уровня (TLS)](https://python-all.ru/3.2/library/ssl.html)**742>743> Blake-Wilson et. al.744