Перейти к содержимому

18.2. ssl – обёртка TLS/SSL для сокетов

Исходный код: Lib/ssl.py


Этот модуль предоставляет доступ к шифрованию и проверке подлинности партнёров (peer authentication) для сетевых сокетов с использованием протокола Transport Layer Security (часто называемого «Secure Sockets Layer»), как на стороне клиента, так и на стороне сервера. Модуль использует библиотеку OpenSSL. Он доступен на всех современных Unix-системах, Windows, Mac OS X и, вероятно, на других платформах при условии, что на них установлена OpenSSL.

Примечание

Некоторые особенности поведения могут зависеть от платформы, так как вызовы осуществляются к API сокетов операционной системы. Установленная версия OpenSSL также может вызывать различия в поведении. Например, TLSv1.1 и TLSv1.2 доступны начиная с openssl версии 1.0.1.

Предупреждение

Не используйте этот модуль, не прочитав Рекомендации по безопасности. В противном случае это может привести к ложному чувству безопасности, поскольку настройки по умолчанию модуля ssl не обязательно подходят для вашего приложения.

В этом разделе документированы объекты и функции модуля ssl; для получения более общей информации о TLS, SSL и сертификатах читатель отсылается к документам в разделе «См. также» внизу.

Этот модуль предоставляет класс ssl.SSLSocket, производный от типа socket.socket, и предоставляет обёртку, подобную сокету, которая также шифрует и расшифровывает данные, передаваемые через сокет с помощью SSL. Он поддерживает дополнительные методы, такие как getpeercert(), который получает сертификат другой стороны соединения, и cipher(), который получает шифр, используемый для защищённого соединения.

Для более сложных приложений класс ssl.SSLContext помогает управлять настройками и сертификатами, которые затем могут быть унаследованы SSL-сокетами, созданными через метод SSLContext.wrap_socket().

Изменено в версии 3.5.3: Обновлено для поддержки компоновки с OpenSSL 1.1.0

Изменено в версии 3.6: OpenSSL 0.9.8, 1.0.0 и 1.0.1 устарели и больше не поддерживаются. В будущем модуль ssl будет требовать как минимум OpenSSL 1.0.2 или 1.1.0.

18.2.1. Функции, константы и исключения

exceptionssl.SSLError

Возникает при ошибке в нижележащей реализации SSL (в настоящее время предоставляемой библиотекой OpenSSL). Это указывает на проблему в высокоуровневом уровне шифрования и аутентификации, который наложен на нижележащее сетевое соединение. Эта ошибка является подтипом OSError. Код ошибки и сообщение экземпляров SSLError предоставляются библиотекой OpenSSL.

Изменено в версии 3.3: SSLError раньше был подтипом socket.error.

library

Строковое мнемоническое обозначение подмодуля OpenSSL, в котором произошла ошибка, например SSL, PEM или X509. Набор возможных значений зависит от версии OpenSSL.

Новое в версии 3.3.

reason

Строковое мнемоническое обозначение причины этой ошибки, например CERTIFICATE_VERIFY_FAILED. Набор возможных значений зависит от версии OpenSSL.

Новое в версии 3.3.

exceptionssl.SSLZeroReturnError

Подкласс SSLError, возникающий при попытке чтения или записи, когда SSL-соединение было корректно закрыто. Обратите внимание, что это не означает, что нижележащий транспорт (например, TCP) был закрыт.

Новое в версии 3.3.

exceptionssl.SSLWantReadError

Подкласс SSLError, возбуждаемый неблокирующим SSL-сокетом при попытке чтения или записи данных, но до выполнения запроса необходимо получить больше данных по нижележащему TCP-транспорту.

Новое в версии 3.3.

exceptionssl.SSLWantWriteError

Подкласс SSLError, возбуждаемый неблокирующим SSL-сокетом при попытке чтения или записи данных, но до выполнения запроса необходимо отправить больше данных по нижележащему TCP-транспорту.

Новое в версии 3.3.

exceptionssl.SSLSyscallError

Подкласс SSLError, возникающий при обнаружении системной ошибки при попытке выполнить операцию с SSL-сокетом. К сожалению, нет простого способа узнать исходный номер errno.

Новое в версии 3.3.

exceptionssl.SSLEOFError

Подкласс SSLError, возникающий при внезапном разрыве SSL-соединения. Как правило, при возникновении этой ошибки не следует пытаться повторно использовать нижележащий транспорт.

Новое в версии 3.3.

exceptionssl.CertificateError

Возбуждается при ошибке с сертификатом (например, несовпадение имени хоста). Однако ошибки сертификата, обнаруженные OpenSSL, вызывают SSLError.

18.2.1.1. Создание сокета

Следующая функция позволяет создавать автономные сокеты. Начиная с Python 3.2, может быть более гибким использовать SSLContext.wrap_socket().

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)

Принимает экземпляр sock класса socket.socket и возвращает экземпляр ssl.SSLSocket, подтип socket.socket, который оборачивает базовый сокет в контекст SSL. sock должен быть сокетом SOCK_STREAM; другие типы сокетов не поддерживаются.

Для клиентских сокетов построение контекста является ленивым; если базовый сокет ещё не подключён, построение контекста будет выполнено после вызова connect() на сокете. Для серверных сокетов, если сокет не имеет удалённого узла, предполагается, что это прослушивающий сокет, и серверная SSL-обёртка автоматически выполняется для клиентских подключений, принятых через метод accept(). wrap_socket() может вызвать SSLError.

Параметры keyfile и certfile задают необязательные файлы, содержащие сертификат, используемый для идентификации локальной стороны соединения. См. обсуждение в разделе Сертификаты для получения дополнительной информации о том, как сертификат хранится в certfile.

Параметр server_side – логическое значение, определяющее, требуется ли от этого сокета поведение сервера или клиента.

Параметр cert_reqs определяет, требуется ли сертификат от другой стороны соединения и будет ли он проверен, если предоставлен. Он должен быть одним из трёх значений: CERT_NONE (сертификаты игнорируются), CERT_OPTIONAL (не требуется, но проверяется, если предоставлен) или CERT_REQUIRED (требуется и проверяется). Если значение этого параметра не равно CERT_NONE, то параметр ca_certs должен указывать на файл сертификатов ЦС.

Файл ca_certs содержит набор объединённых сертификатов «центров сертификации», которые используются для проверки сертификатов, поступивших с другого конца соединения. См. обсуждение в разделе Сертификаты для получения дополнительной информации о размещении сертификатов в этом файле.

Параметр ssl_version указывает, какую версию протокола SSL использовать. Обычно сервер выбирает определённую версию протокола, а клиент должен адаптироваться к выбору сервера. Большинство версий несовместимы друг с другом. Если не указано, по умолчанию используется PROTOCOL_TLS, который обеспечивает наибольшую совместимость с другими версиями.

Ниже приведена таблица, показывающая, какие версии на стороне клиента (по левой стороне) могут подключаться к каким версиям на стороне сервера (по верхней стороне):

клиент / сервер

SSLv2

SSLv3

TLS 3

TLSv1

TLSv1.1

TLSv1.2

SSLv2

да

нет

нет 1

нет

нет

нет

SSLv3

нет

да

нет 2

нет

нет

нет

TLS (SSLv23) 3

нет 1

нет 2

да

да

да

да

TLSv1

нет

нет

да

да

нет

нет

TLSv1.1

нет

нет

да

нет

да

нет

TLSv1.2

нет

нет

да

нет

нет

да

Сноски

1(1,2)

SSLContext отключает SSLv2 с OP_NO_SSLv2 по умолчанию.

2(1,2)

SSLContext отключает SSLv3 с OP_NO_SSLv3 по умолчанию.

3(1,2)

Протокол TLS 1.3 будет доступен с PROTOCOL_TLS в OpenSSL >= 1.1.1. Нет отдельной константы PROTOCOL только для TLS 1.3.

Примечание

Какие соединения будут успешными, зависит от версии OpenSSL. Например, до OpenSSL 1.0.0 клиент SSLv23 всегда пытался установить SSLv2-соединения.

Параметр ciphers задаёт доступные шифры для данного SSL-объекта. Это должна быть строка в формате списка шифров OpenSSL.

Параметр do_handshake_on_connect указывает, следует ли выполнять SSL-рукопожатие автоматически после socket.connect(), или же приложение будет вызывать его явно с помощью метода SSLSocket.do_handshake(). Явный вызов SSLSocket.do_handshake() даёт программе контроль над блокирующим поведением ввода-вывода сокета, участвующего в рукопожатии.

Параметр suppress_ragged_eofs определяет, как метод SSLSocket.recv() должен сигнализировать о неожиданном EOF с другого конца соединения. Если указано True (по умолчанию), он возвращает обычный EOF (пустой объект bytes) в ответ на ошибки неожиданного EOF, возникающие от базового сокета; если False, он передаёт исключения обратно вызывающему.

Изменено в версии 3.2: Новый необязательный аргумент ciphers.

18.2.1.2. Создание контекста

Удобная функция помогает создавать объекты SSLContext для общих целей.

ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)

Возвращает новый объект SSLContext с настройками по умолчанию для заданного назначения. Настройки выбираются модулем ssl и обычно представляют более высокий уровень безопасности, чем при прямом вызове конструктора SSLContext.

cafile, capath, cadata представляют необязательные сертификаты ЦС для доверия при проверке сертификатов, как в SSLContext.load_verify_locations(). Если все три равны None, эта функция может вместо этого доверять системным сертификатам ЦС по умолчанию.

Настройки: PROTOCOL_TLS, OP_NO_SSLv2 и OP_NO_SSLv3 с высокозащищёнными наборами шифров без RC4 и без неаутентифицированных наборов шифров. Передача SERVER_AUTH в качестве purpose устанавливает verify_mode в CERT_REQUIRED и либо загружает сертификаты ЦС (когда задан хотя бы один из cafile, capath или cadata), либо использует SSLContext.load_default_certs() для загрузки сертификатов ЦС по умолчанию.

Примечание

Протокол, параметры, шифры и другие настройки могут в любое время измениться на более строгие значения без предварительного уведомления об устаревании. Эти значения представляют собой разумный баланс между совместимостью и безопасностью.

Если вашему приложению требуются определённые настройки, вам следует создать SSLContext и применить настройки самостоятельно.

Примечание

Если вы обнаружите, что при попытке определённых старых клиентов или серверов подключиться с SSLContext, созданным этой функцией, возникает ошибка «Несовпадение протокола или набора шифров», возможно, они поддерживают только SSL 3.0, который эта функция исключает с помощью OP_NO_SSLv3. SSL 3.0 широко считается полностью взломанным. Если вы всё же хотите продолжать использовать эту функцию, но разрешить подключения SSL 3.0, вы можете снова включить их, используя:

python
ctx = ssl.create_default_context(Purpose.CLIENT_AUTH)
ctx.options &= ~ssl.OP_NO_SSLv3

Новое в версии 3.4.

Изменено в версии 3.4.4: RC4 был удалён из строки шифров по умолчанию.

Изменено в версии 3.6: ChaCha20/Poly1305 был добавлен в строку шифров по умолчанию.

3DES был удалён из строки шифров по умолчанию.

18.2.1.3. Генерация случайных чисел

ssl.RAND_bytes(num)

Возвращает num криптостойких псевдослучайных байт. Возбуждает исключение SSLError, если ГПСЧ не был инициализирован достаточным количеством энтропии или если операция не поддерживается текущим методом RAND. RAND_status() можно использовать для проверки состояния ГПСЧ, а RAND_add() – для его инициализации.

Для большинства приложений предпочтительнее os.urandom().

Прочитайте статью в Википедии «Криптографически стойкий генератор псевдослучайных чисел (CSPRNG)», чтобы узнать требования к криптографическому генератору.

Новое в версии 3.3.

ssl.RAND_pseudo_bytes(num)

Возвращает (bytes, is_cryptographic): bytes – это num псевдослучайных байтов, is_cryptographic равно True, если сгенерированные байты криптографически стойкие. Возбуждает SSLError, если операция не поддерживается текущим методом RAND.

Сгенерированные последовательности псевдослучайных байтов будут уникальными, если они имеют достаточную длину, но не обязательно непредсказуемыми. Их можно использовать для некриптографических целей и для некоторых целей в криптографических протоколах, но обычно не для генерации ключей и т.д.

Для большинства приложений предпочтительнее os.urandom().

Новое в версии 3.3.

Устарело с версии 3.6: OpenSSL объявил устаревшим ssl.RAND_pseudo_bytes(), используйте ssl.RAND_bytes() вместо этого.

ssl.RAND_status()

Возвращает True, если генератор псевдослучайных чисел SSL был инициализирован достаточной случайностью, и False в противном случае. Можно использовать ssl.RAND_egd() и ssl.RAND_add() для увеличения случайности генератора псевдослучайных чисел.

ssl.RAND_egd(путь)

Если вы запустили где-то демон сбора энтропии (EGD) и path – это путь к сокетному соединению с ним, то будет прочитано 256 байт случайности из сокета и добавлено в генератор псевдослучайных чисел SSL для повышения безопасности создаваемых секретных ключей. Обычно это требуется только в системах, не имеющих лучших источников случайности.

Смотрите http://egd.sourceforge.net/ или http://prngd.sourceforge.net/ для получения исходных кодов демонов сбора энтропии.

Доступность: недоступно в LibreSSL и OpenSSL > 1.1.0

ssl.RAND_add(bytes, entropy)

Mix the given bytes into the SSL pseudo-random number generator. The parameter entropy (a float) is a lower bound on the entropy contained in string (so you can always use 0.0). See RFC 1750 for more information on sources of entropy.

Изменено в версии 3.5: Теперь принимается записываемый байтоподобный объект.

18.2.1.4. Обработка сертификатов

ssl.match_hostname(cert, hostname)

Проверяет, что cert (в декодированном формате, возвращаемом SSLSocket.getpeercert()) соответствует заданному hostname. Применяются правила проверки подлинности HTTPS-серверов, описанные в RFC 2818, RFC 5280 и RFC 6125. В дополнение к HTTPS эта функция подходит для проверки подлинности серверов в различных протоколах на основе SSL, таких как FTPS, IMAPS, POPS и других.

CertificateError возбуждается при ошибке. При успехе функция ничего не возвращает:

python
>>> cert = {'subject': ((('commonName', 'example.com'),),)}
>>> ssl.match_hostname(cert, "example.com")
>>> ssl.match_hostname(cert, "example.org")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/py3k/Lib/ssl.py", line 130, in match_hostname
ssl.CertificateError: hostname 'example.org' doesn't match 'example.com'

Новое в версии 3.2.

Изменено в версии 3.3.3: Теперь функция следует RFC 6125, раздел 6.4.3, и не соответствует множественным шаблонам (например, *.*.com или *a*.example.org), а также шаблону внутри фрагмента интернационализированного доменного имени (IDN). IDN A-метки, такие как www*.xn--pthon-kva.org, по-прежнему поддерживаются, но x*.python.org больше не соответствует xn--tda.python.org.

Изменено в версии 3.5: Теперь поддерживается сопоставление IP-адресов, если они присутствуют в поле subjectAltName сертификата.

ssl.cert_time_to_seconds(cert_time)

Возвращает время в секундах с начала эпохи (Epoch) для строки cert_time, представляющей дату «notBefore» или «notAfter» из сертификата в формате strptime "%b %d %H:%M:%S %Y %Z" (локаль C).

Пример:

pycon3
>>> import ssl
>>> timestamp = ssl.cert_time_to_seconds("Jan  5 09:34:43 2018 GMT")
>>> timestamp
1515144883
>>> from datetime import datetime
>>> print(datetime.utcfromtimestamp(timestamp))
2018-01-05 09:34:43

“notBefore” or “notAfter” dates must use GMT (RFC 5280).

Изменено в версии 3.5: Входное время теперь интерпретируется как время в UTC, как указано часовым поясом «GMT» во входной строке. Ранее использовался местный часовой пояс. Возвращает целое число (без долей секунды во входном формате).

ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)

По заданному адресу addr SSL-защищённого сервера в виде пары (имя_хоста, порт) получает сертификат сервера и возвращает его в виде строки в формате PEM. Если указан ssl_version, используется указанная версия протокола SSL для попытки подключения к серверу. Если указан ca_certs, это должен быть файл, содержащий список корневых сертификатов, в том же формате, что используется для того же параметра в wrap_socket(). Вызов попытается проверить сертификат сервера относительно этого набора корневых сертификатов, и завершится ошибкой, если проверка не удастся.

Изменено в версии 3.3: Эта функция теперь совместима с IPv6.

Изменено в версии 3.5: Значение по умолчанию для ssl_version изменено с PROTOCOL_SSLv3 на PROTOCOL_TLS для максимальной совместимости с современными серверами.

ssl.DER_cert_to_PEM_cert(DER_cert_bytes)

Принимает сертификат в виде DER-закодированного блока байт и возвращает версию того же сертификата в виде строки в формате PEM.

ssl.PEM_cert_to_DER_cert(PEM_cert_string)

Принимает сертификат в виде ASCII-строки в формате PEM и возвращает последовательность байт, закодированную в DER, для того же сертификата.

ssl.get_default_verify_paths()

Returns a named tuple with paths to OpenSSL’s default cafile and capath. The paths are the same as used by SSLContext.set_default_verify_paths(). The return value is a named tuple DefaultVerifyPaths:

  • cafile – полный путь к cafile или None, если файл не существует,

  • capath – полный путь к capath или None, если каталог не существует,

  • openssl_cafile_env – переменная окружения OpenSSL, указывающая на cafile,

  • openssl_cafile – жёстко заданный путь к cafile,

  • openssl_capath_env – переменная окружения OpenSSL, указывающая на capath,

  • openssl_capath – жёстко заданный путь к каталогу capath

Доступность: LibreSSL игнорирует переменные окружения openssl_cafile_env и openssl_capath_env

Новое в версии 3.4.

ssl.enum_certificates(store_name)

Извлекает сертификаты из системного хранилища сертификатов Windows. store_name может быть одним из CA, ROOT или MY. Windows также может предоставлять дополнительные хранилища сертификатов.

Функция возвращает список кортежей (cert_bytes, encoding_type, trust). Параметр encoding_type указывает кодировку cert_bytes. Это может быть x509_asn для данных X.509 ASN.1 или pkcs_7_asn для данных PKCS#7 ASN.1. Параметр trust задаёт назначение сертификата в виде набора OID или ровно True, если сертификат является доверенным для всех целей.

Пример:

python
>>> ssl.enum_certificates("CA")
[(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}),
 (b'data...', 'x509_asn', True)]

Доступность: Windows.

Новое в версии 3.4.

ssl.enum_crls(store_name)

Извлекает списки отзыва сертификатов (CRL) из системного хранилища сертификатов Windows. store_name может быть одним из CA, ROOT или MY. Windows также может предоставлять дополнительные хранилища сертификатов.

Функция возвращает список кортежей (cert_bytes, encoding_type, trust). Параметр encoding_type указывает кодировку cert_bytes. Это может быть x509_asn для данных X.509 ASN.1 или pkcs_7_asn для данных PKCS#7 ASN.1.

Доступность: Windows.

Новое в версии 3.4.

18.2.1.5. Константы

Все константы теперь являются коллекциями enum.IntEnum или enum.IntFlag.

Новое в версии 3.6.

ssl.CERT_NONE

Возможное значение для SSLContext.verify_mode или параметра cert_reqs в wrap_socket(). За исключением PROTOCOL_TLS_CLIENT, это режим по умолчанию. Для клиентских сокетов принимается практически любой сертификат. Ошибки проверки, такие как ненадёжный или просроченный сертификат, игнорируются и не прерывают рукопожатие TLS/SSL.

В режиме сервера у клиента не запрашивается сертификат, поэтому клиент не отправляет никакой для аутентификации по клиентскому сертификату.

Смотрите обсуждение Вопросов безопасности ниже.

ssl.CERT_OPTIONAL

Возможное значение для SSLContext.verify_mode или параметра cert_reqs в wrap_socket(). В клиентском режиме CERT_OPTIONAL имеет тот же смысл, что и CERT_REQUIRED. Вместо этого рекомендуется использовать CERT_REQUIRED для клиентских сокетов.

В режиме сервера клиенту отправляется запрос сертификата. Клиент может либо проигнорировать запрос, либо отправить сертификат для выполнения аутентификации по клиентскому сертификату TLS. Если клиент решает отправить сертификат, он проверяется. Любая ошибка проверки немедленно прерывает рукопожатие TLS.

Использование этой настройки требует передачи действительного набора сертификатов CA в SSLContext.load_verify_locations() или в качестве значения параметра ca_certs в wrap_socket().

ssl.CERT_REQUIRED

Возможное значение для SSLContext.verify_mode или параметра cert_reqs в wrap_socket(). В этом режиме от другой стороны сокетного соединения требуются сертификаты; если сертификат не предоставлен или его проверка не удалась, будет возбуждено SSLError. Этот режим не достаточен для проверки сертификата в клиентском режиме, так как не сопоставляет имена хостов. check_hostname также должен быть включён для проверки подлинности сертификата. PROTOCOL_TLS_CLIENT использует CERT_REQUIRED и по умолчанию включает check_hostname.

В серверном сокете этот режим обеспечивает обязательную аутентификацию клиента по сертификату TLS. Клиенту отправляется запрос сертификата, и клиент должен предоставить действительный и доверенный сертификат.

Использование этой настройки требует передачи действительного набора сертификатов CA в SSLContext.load_verify_locations() или в качестве значения параметра ca_certs в wrap_socket().

classssl.VerifyMode

Коллекция enum.IntEnum констант CERT_*.

Новое в версии 3.6.

ssl.VERIFY_DEFAULT

Возможное значение для SSLContext.verify_flags. В этом режиме списки отзыва сертификатов (CRL) не проверяются. По умолчанию OpenSSL не требует и не проверяет CRL.

Новое в версии 3.4.

ssl.VERIFY_CRL_CHECK_LEAF

Возможное значение для SSLContext.verify_flags. В этом режиме проверяется только сертификат однорангового узла, но ни один из промежуточных сертификатов ЦС. Режим требует действительный CRL, подписанный издателем сертификата однорангового узла (его непосредственным вышестоящим ЦС). Если не загружен подходящий SSLContext.load_verify_locations, проверка завершится ошибкой.

Новое в версии 3.4.

ssl.VERIFY_CRL_CHECK_CHAIN

Возможное значение для SSLContext.verify_flags. В этом режиме проверяются CRL всех сертификатов в цепочке сертификатов однорангового узла.

Новое в версии 3.4.

ssl.VERIFY_X509_STRICT

Возможное значение для SSLContext.verify_flags, отключающее обходные решения для некорректных X.509 сертификатов.

Новое в версии 3.4.

ssl.VERIFY_X509_TRUSTED_FIRST

Возможное значение для SSLContext.verify_flags. Указывает OpenSSL предпочитать доверенные сертификаты при построении цепочки доверия для проверки сертификата. Этот флаг включён по умолчанию.

Новое в версии 3.4.4.

classssl.VerifyFlags

enum.IntFlag набор констант VERIFY_*.

Новое в версии 3.6.

ssl.PROTOCOL_TLS

Выбирает самую высокую версию протокола, поддерживаемую как клиентом, так и сервером. Несмотря на название, этот параметр может выбирать как протоколы «SSL», так и «TLS».

Новое в версии 3.6.

ssl.PROTOCOL_TLS_CLIENT

Автоматически согласовывать самую высокую версию протокола, как PROTOCOL_TLS, но поддерживать только клиентские SSLSocket соединения. Протокол по умолчанию включает CERT_REQUIRED и check_hostname.

Новое в версии 3.6.

ssl.PROTOCOL_TLS_SERVER

Автоматически согласовывать самую высокую версию протокола, как PROTOCOL_TLS, но поддерживать только серверные SSLSocket соединения.

Новое в версии 3.6.

ssl.PROTOCOL_SSLv23

Псевдоним для data:PROTOCOL_TLS.

Устарело с версии 3.6: Используйте PROTOCOL_TLS вместо этого.

ssl.PROTOCOL_SSLv2

Выбирает протокол SSL версии 2 в качестве протокола шифрования канала.

Этот протокол недоступен, если OpenSSL скомпилирован с флагом OPENSSL_NO_SSL2.

Предупреждение

SSL версии 2 небезопасен. Его использование крайне не рекомендуется.

Устарело с версии 3.6: OpenSSL удалила поддержку SSLv2.

ssl.PROTOCOL_SSLv3

Выбирает SSL версии 3 в качестве протокола шифрования канала.

Этот протокол недоступен, если OpenSSL скомпилирован с флагом OPENSSL_NO_SSLv3.

Предупреждение

SSL версии 3 небезопасен. Его использование крайне не рекомендуется.

Устарело с версии 3.6: OpenSSL объявил устаревшими все версие-специфичные протоколы. Вместо этого используйте протокол по умолчанию PROTOCOL_TLS с флагами, такими как OP_NO_SSLv3.

ssl.PROTOCOL_TLSv1

Выбирает TLS версии 1.0 в качестве протокола шифрования канала.

Устарело с версии 3.6: OpenSSL объявил устаревшими все версие-специфичные протоколы. Вместо этого используйте протокол по умолчанию PROTOCOL_TLS с флагами, такими как OP_NO_SSLv3.

ssl.PROTOCOL_TLSv1_1

Выбирает TLS версии 1.1 в качестве протокола шифрования канала. Доступен только с openssl версии 1.0.1+.

Новое в версии 3.4.

Устарело с версии 3.6: OpenSSL объявил устаревшими все версие-специфичные протоколы. Вместо этого используйте протокол по умолчанию PROTOCOL_TLS с флагами, такими как OP_NO_SSLv3.

ssl.PROTOCOL_TLSv1_2

Выбирает TLS версии 1.2 в качестве протокола шифрования канала. Это самая современная версия, и, вероятно, наилучший выбор для максимальной защиты, если обе стороны её поддерживают. Доступна только с openssl версии 1.0.1 и выше.

Новое в версии 3.4.

Устарело с версии 3.6: OpenSSL объявил устаревшими все версие-специфичные протоколы. Вместо этого используйте протокол по умолчанию PROTOCOL_TLS с флагами, такими как OP_NO_SSLv3.

ssl.OP_ALL

Включает обходные пути для различных ошибок, присутствующих в других реализациях SSL. Эта опция установлена по умолчанию. Она не обязательно устанавливает те же флаги, что и константа SSL_OP_ALL в OpenSSL.

Новое в версии 3.2.

ssl.OP_NO_SSLv2

Предотвращает соединение SSLv2. Этот параметр применим только в сочетании с PROTOCOL_TLS. Он не позволяет сторонам выбирать SSLv2 в качестве версии протокола.

Новое в версии 3.2.

Устарело с версии 3.6: SSLv2 устарел

ssl.OP_NO_SSLv3

Предотвращает соединение по SSLv3. Этот параметр применим только вместе с PROTOCOL_TLS. Он не позволяет пирам выбирать SSLv3 в качестве версии протокола.

Новое в версии 3.2.

Устарело с версии 3.6: SSLv3 устарел

ssl.OP_NO_TLSv1

Предотвращает соединение по TLSv1. Этот параметр применим только вместе с PROTOCOL_TLS. Он не позволяет пирам выбирать TLSv1 в качестве версии протокола.

Новое в версии 3.2.

ssl.OP_NO_TLSv1_1

Предотвращает соединение по TLSv1.1. Этот параметр применим только вместе с PROTOCOL_TLS. Он не позволяет пирам выбирать TLSv1.1 в качестве версии протокола. Доступно только в openssl версии 1.0.1+.

Новое в версии 3.4.

ssl.OP_NO_TLSv1_2

Предотвращает соединение по TLSv1.2. Этот параметр применим только вместе с PROTOCOL_TLS. Он не позволяет пирам выбирать TLSv1.2 в качестве версии протокола. Доступно только в openssl версии 1.0.1+.

Новое в версии 3.4.

ssl.OP_NO_TLSv1_3

Предотвращает соединение по TLSv1.3. Этот параметр применим только вместе с PROTOCOL_TLS. Он не позволяет пирам выбирать TLSv1.3 в качестве версии протокола. TLS 1.3 доступен в OpenSSL 1.1.1 и новее. Если Python скомпилирован с более старой версией OpenSSL, флаг по умолчанию равен 0.

Новое в версии 3.6.3.

ssl.OP_CIPHER_SERVER_PREFERENCE

Использовать порядок предпочтения шифров сервера, а не клиента. Этот параметр не влияет на клиентские сокеты и серверные сокеты SSLv2.

Новое в версии 3.3.

ssl.OP_SINGLE_DH_USE

Предотвращает повторное использование одного и того же DH-ключа для разных SSL-сеансов. Это улучшает прямую секретность, но требует больше вычислительных ресурсов. Данная опция применима только к серверным сокетам.

Новое в версии 3.3.

ssl.OP_SINGLE_ECDH_USE

Предотвращает повторное использование одного и того же ECDH-ключа для разных SSL-сеансов. Это улучшает прямую секретность, но требует больше вычислительных ресурсов. Данная опция применима только к серверным сокетам.

Новое в версии 3.3.

ssl.OP_ENABLE_MIDDLEBOX_COMPAT

Отправляет фиктивные сообщения Change Cipher Spec (CCS) в процессе рукопожатия TLS 1.3, чтобы соединение TLS 1.3 выглядело больше как соединение TLS 1.2.

Этот параметр доступен только в OpenSSL 1.1.1 и новее.

Новое в версии 3.6.7.

ssl.OP_NO_COMPRESSION

Отключает сжатие на SSL-канале. Это полезно, если протокол приложения поддерживает собственную схему сжатия.

Эта опция доступна только в OpenSSL 1.0.0 и более поздних версиях.

Новое в версии 3.3.

classssl.Options

enum.IntFlag коллекция констант OP_*.

ssl.OP_NO_TICKET

Предотвращает запрос сессионного билета со стороны клиента.

Новое в версии 3.6.

ssl.HAS_ALPN

Указывает, имеет ли библиотека OpenSSL встроенную поддержку расширения TLS Согласование протокола прикладного уровня, описанного в RFC 7301.

Новое в версии 3.5.

ssl.HAS_ECDH

Определяет, имеет ли библиотека OpenSSL встроенную поддержку обмена ключами Диффи-Хеллмана на основе эллиптических кривых. Должно быть истинно, если только эта возможность не была явно отключена дистрибьютором.

Новое в версии 3.3.

ssl.HAS_SNI

Указывает, имеет ли библиотека OpenSSL встроенную поддержку расширения Server Name Indication (определённого в RFC 6066).

Новое в версии 3.2.

ssl.HAS_NPN

Определяет, имеет ли библиотека OpenSSL встроенную поддержку согласования следующего протокола, как описано в черновике спецификации NPN. Если истинно, вы можете использовать метод SSLContext.set_npn_protocols() для объявления протоколов, которые вы хотите поддерживать.

Новое в версии 3.3.

ssl.HAS_TLSv1_3

Указывает, имеет ли библиотека OpenSSL встроенную поддержку протокола TLS 1.3.

Новое в версии 3.6.3.

ssl.CHANNEL_BINDING_TYPES

Список поддерживаемых типов привязки каналов TLS. Строки из этого списка могут использоваться как аргументы для SSLSocket.get_channel_binding().

Новое в версии 3.3.

ssl.OPENSSL_VERSION

Строка версии библиотеки OpenSSL, загруженной интерпретатором:

python
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.0.2k  26 Jan 2017'

Новое в версии 3.2.

ssl.OPENSSL_VERSION_INFO

Кортеж из пяти целых чисел, представляющий информацию о версии библиотеки OpenSSL:

python
>>> ssl.OPENSSL_VERSION_INFO
(1, 0, 2, 11, 15)

Новое в версии 3.2.

ssl.OPENSSL_VERSION_NUMBER

Сырой номер версии библиотеки OpenSSL в виде одного целого числа:

python
>>> ssl.OPENSSL_VERSION_NUMBER
268443839
>>> hex(ssl.OPENSSL_VERSION_NUMBER)
'0x100020bf'

Новое в версии 3.2.

ssl.ALERT_DESCRIPTION_HANDSHAKE_FAILURE
ssl.ALERT_DESCRIPTION_INTERNAL_ERROR
ALERT_DESCRIPTION_*

Описания оповещений из RFC 5246 и других источников. Реестр оповещений TLS IANA TLS Alert Registry содержит этот список и ссылки на RFC, где определено их значение.

Используется как возвращаемое значение колбэка в SSLContext.set_servername_callback().

Новое в версии 3.4.

classssl.AlertDescription

enum.IntEnum – коллекция констант ALERT_DESCRIPTION_*.

Новое в версии 3.6.

Purpose.SERVER_AUTH

Опция для create_default_context() и SSLContext.load_default_certs(). Это значение указывает, что контекст может использоваться для аутентификации веб-серверов (следовательно, он будет использоваться для создания клиентских сокетов).

Новое в версии 3.4.

Purpose.CLIENT_AUTH

Опция для create_default_context() и SSLContext.load_default_certs(). Это значение указывает, что контекст может использоваться для аутентификации веб-клиентов (поэтому он будет использоваться для создания серверных сокетов).

Новое в версии 3.4.

classssl.SSLErrorNumber

enum.IntEnum – коллекция констант SSL_ERROR_*.

Новое в версии 3.6.

18.2.2. SSL-сокеты

classssl.SSLSocket(socket.socket)

SSL сокеты предоставляют следующие методы объектов сокетов:

Однако, поскольку протокол SSL (и TLS) имеет свою собственную структуру кадров поверх TCP, абстракция SSL-сокетов в некоторых аспектах может отличаться от спецификации обычных сокетов уровня ОС. См. особенно примечания о неблокирующих сокетах.

Обычно SSLSocket не создаются напрямую, а с помощью метода SSLContext.wrap_socket().

Изменено в версии 3.5: Метод sendfile() был добавлен.

Изменено в версии 3.5: shutdown() больше не сбрасывает тайм-аут сокета каждый раз, когда байты получаются или отправляются. Тайм-аут сокета теперь указывает на максимальную общую продолжительность завершения соединения.

Устарело с версии 3.6: Создавать экземпляр SSLSocket напрямую устарело; используйте SSLContext.wrap_socket() для обёртывания сокета.

SSL-сокеты также имеют следующие дополнительные методы и атрибуты:

SSLSocket.read(len=1024, buffer=None)

Читает до len байт данных из SSL-сокета и возвращает результат в виде экземпляра bytes. Если указан buffer, то читает в буфер и возвращает количество прочитанных байтов.

Вызывает исключение SSLWantReadError или SSLWantWriteError, если сокет неблокирующий и чтение привело бы к блокировке.

Так как в любой момент возможна повторная аутентификация (re-negotiation), вызов read() может также инициировать операции записи.

Изменено в версии 3.5: Тайм-аут сокета больше не сбрасывается каждый раз при получении или отправке байтов. Тайм-аут сокета теперь указывает на максимальную общую продолжительность чтения до len байт.

Устарело с версии 3.6: Используйте recv() вместо read().

SSLSocket.write(buf)

Записывает buf в SSL-сокет и возвращает количество записанных байт. Аргумент buf должен быть объектом, поддерживающим буферный интерфейс.

Вызывает SSLWantReadError или SSLWantWriteError, если сокет неблокирующий и запись будет заблокирована.

Поскольку повторное согласование возможно в любой момент, вызов write() может также вызывать операции чтения.

Изменено в версии 3.5: Тайм-аут сокета больше не сбрасывается каждый раз при получении или отправке байтов. Тайм-аут сокета теперь указывает на максимальную общую продолжительность записи buf.

Устарело с версии 3.6: Используйте send() вместо write().

Примечание

Методы read() и write() являются низкоуровневыми методами, которые читают и записывают незашифрованные данные прикладного уровня и расшифровывают/шифруют их в зашифрованные данные уровня передачи. Эти методы требуют активного SSL-соединения, т.е. рукопожатие выполнено и SSLSocket.unwrap() не вызывался.

Обычно вместо этих методов следует использовать методы сокетного API, такие как recv() и send().

SSLSocket.do_handshake()

Выполняет рукопожатие настройки SSL.

Изменено в версии 3.4: Метод рукопожатия также выполняет match_hostname(), когда атрибут check_hostname объекта context сокета равен true.

Изменено в версии 3.5: Тайм-аут сокета больше не сбрасывается каждый раз при получении или отправке байтов. Тайм-аут сокета теперь указывает на максимальную общую продолжительность рукопожатия.

SSLSocket.getpeercert(binary_form=False)

Если для удаленной стороны на другом конце соединения нет сертификата, возвращает None. Если рукопожатие SSL еще не выполнено, вызывает ValueError.

Если параметр binary_form равен False и от удаленной стороны был получен сертификат, этот метод возвращает экземпляр dict. Если сертификат не был проверен, словарь пуст. Если сертификат был проверен, возвращается словарь с несколькими ключами, среди которых subject (субъект, на который выдан сертификат) и issuer (субъект, выпустивший сертификат). Если сертификат содержит экземпляр расширения Subject Alternative Name (см. RFC 3280), в словаре также будет ключ subjectAltName.

Поля subject и issuer представляют собой кортежи, содержащие последовательность относительных отличительных имен (RDN) в структуре данных сертификата для соответствующих полей, и каждый RDN представляет собой последовательность пар имя-значение. Вот пример из реального мира:

python
{'issuer': ((('countryName', 'IL'),),
            (('organizationName', 'StartCom Ltd.'),),
            (('organizationalUnitName',
              'Secure Digital Certificate Signing'),),
            (('commonName',
              'StartCom Class 2 Primary Intermediate Server CA'),)),
 'notAfter': 'Nov 22 08:15:19 2013 GMT',
 'notBefore': 'Nov 21 03:09:52 2011 GMT',
 'serialNumber': '95F0',
 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),),
             (('countryName', 'US'),),
             (('stateOrProvinceName', 'California'),),
             (('localityName', 'San Francisco'),),
             (('organizationName', 'Electronic Frontier Foundation, Inc.'),),
             (('commonName', '*.eff.org'),),
             (('emailAddress', 'hostmaster@eff.org'),)),
 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')),
 'version': 3}

Примечание

Чтобы проверить сертификат для конкретного сервиса, можно использовать функцию match_hostname().

Если параметр binary_form равен True и сертификат был предоставлен, этот метод возвращает DER-кодированную форму всего сертификата в виде последовательности байтов или None, если удаленная сторона не предоставила сертификата. Предоставляет ли удаленная сторона сертификат, зависит от роли SSL-сокета:

  • для клиентского SSL-сокета сервер всегда предоставляет сертификат, независимо от того, требовалась ли проверка;

  • для серверного SSL-сокета клиент предоставляет сертификат только по запросу сервера; следовательно, getpeercert() вернет None, если вы использовали CERT_NONE (а не CERT_OPTIONAL или CERT_REQUIRED).

Изменено в версии 3.2: Возвращаемый словарь включает дополнительные элементы, такие как issuer и notBefore.

Изменено в версии 3.4: ValueError вызывается, когда рукопожатие не выполнено. Возвращаемый словарь включает дополнительные элементы расширений X509v3, такие как crlDistributionPoints, caIssuers и OCSP URI.

SSLSocket.cipher()

Возвращает кортеж из трех значений, содержащий имя используемого шифра, версию протокола SSL, которая определяет его использование, и количество используемых секретных битов. Если соединение не было установлено, возвращает None.

SSLSocket.shared_ciphers()

Возвращает список шифров, переданных клиентом во время рукопожатия. Каждый элемент возвращённого списка – это кортеж из трёх значений, содержащий имя шифра, версию протокола SSL, определяющую его использование, и количество битов секретного ключа, используемых шифром. shared_ciphers() возвращает None, если соединение не установлено или сокет является клиентским сокетом.

Новое в версии 3.5.

SSLSocket.compression()

Возвращает используемый алгоритм сжатия в виде строки или None, если соединение не сжато.

Если протокол более высокого уровня поддерживает собственный механизм сжатия, можно использовать OP_NO_COMPRESSION для отключения сжатия на уровне SSL.

Новое в версии 3.3.

SSLSocket.get_channel_binding(cb_type="tls-unique")

Возвращает данные привязки канала для текущего соединения в виде объекта bytes. Возвращает None, если соединение не установлено или рукопожатие не завершено.

The cb_type parameter allow selection of the desired channel binding type. Valid channel binding types are listed in the CHANNEL_BINDING_TYPES list. Currently only the ‘tls-unique’ channel binding, defined by RFC 5929, is supported. ValueError will be raised if an unsupported channel binding type is requested.

Новое в версии 3.3.

SSLSocket.selected_alpn_protocol()

Возвращает протокол, выбранный во время рукопожатия TLS. Если SSLContext.set_alpn_protocols() не был вызван, другая сторона не поддерживает ALPN, данный сокет не поддерживает ни один из предложенных клиентом протоколов или рукопожатие ещё не произошло, возвращается None.

Новое в версии 3.5.

SSLSocket.selected_npn_protocol()

Возвращает протокол более высокого уровня, выбранный во время рукопожатия TLS/SSL. Если SSLContext.set_npn_protocols() не был вызван, другая сторона не поддерживает NPN или рукопожатие ещё не произошло, возвращается None.

Новое в версии 3.3.

SSLSocket.unwrap()

Выполняет процедуру завершения SSL, которая удаляет уровень TLS из нижележащего сокета и возвращает объект нижележащего сокета. Это можно использовать для перехода от зашифрованной работы через соединение к незашифрованной. Возвращённый сокет всегда следует использовать для дальнейшего обмена данными с другой стороной соединения вместо исходного сокета.

SSLSocket.verify_client_post_handshake()

Запрашивает аутентификацию после рукопожатия (PHA) у клиента TLS 1.3. PHA может быть инициирована только для соединения TLS 1.3 со стороны серверного сокета, после начального рукопожатия TLS и при включённой PHA с обеих сторон; см. SSLContext.post_handshake_auth.

Метод не выполняет обмен сертификатами немедленно. Серверная сторона отправляет CertificateRequest во время следующего события записи и ожидает, что клиент ответит сертификатом при следующем событии чтения.

Если какое-либо предусловие не выполнено (например, не TLS 1.3, PHA не включена), возбуждается SSLError.

Новое в версии 3.6.7.

Примечание

Доступно только при наличии OpenSSL 1.1.1 и включённом TLS 1.3. Без поддержки TLS 1.3 метод возбуждает NotImplementedError.

SSLSocket.version()

Возвращает фактическую версию протокола SSL, согласованную соединением, в виде строки, или None, если безопасное соединение не установлено. На момент написания возможные возвращаемые значения включают "SSLv2", "SSLv3", "TLSv1", "TLSv1.1" и "TLSv1.2". В новых версиях OpenSSL могут быть определены дополнительные возвращаемые значения.

Новое в версии 3.5.

SSLSocket.pending()

Возвращает количество уже расшифрованных байтов, доступных для чтения и ожидающих обработки в соединении.

SSLSocket.context

Объект SSLContext, к которому привязан данный SSL-сокет. Если SSL-сокет был создан с использованием функции верхнего уровня wrap_socket() (а не SSLContext.wrap_socket()), то это пользовательский объект контекста, созданный для этого SSL-сокета.

Новое в версии 3.2.

SSLSocket.server_side

Логическое значение, равное True для сокетов на стороне сервера и False для сокетов на стороне клиента.

Новое в версии 3.2.

SSLSocket.server_hostname

Имя хоста сервера: тип str или None для сокета на стороне сервера, если имя хоста не было указано в конструкторе.

Новое в версии 3.2.

SSLSocket.session

SSLSession для этого SSL-соединения. Сессия доступна для сокетов на стороне клиента и сервера после выполнения рукопожатия TLS. Для клиентских сокетов сессию можно установить до вызова do_handshake(), чтобы повторно использовать сессию.

Новое в версии 3.6.

SSLSocket.session_reused

Новое в версии 3.6.

18.2.3. Контексты SSL

Новое в версии 3.2.

SSL-контекст хранит различные данные, время жизни которых больше, чем у отдельных SSL-соединений, такие как параметры SSL-конфигурации, сертификаты и закрытые ключи. Он также управляет кэшем SSL-сессий для сокетов на стороне сервера, чтобы ускорить повторные соединения от одних и тех же клиентов.

classssl.SSLContext(protocol=PROTOCOL_TLS)

Создаёт новый контекст SSL. Вы можете передать протокол, который должен быть одной из констант PROTOCOL_*, определённых в этом модуле. В настоящее время для максимальной совместимости рекомендуется PROTOCOL_TLS, и оно является значением по умолчанию.

Смотрите также

create_default_context() позволяет модулю ssl выбирать параметры безопасности для заданной цели.

Изменено в версии 3.6: Контекст создаётся с безопасными значениями по умолчанию. По умолчанию установлены параметры OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE, OP_NO_SSLv2 (за исключением PROTOCOL_SSLv2) и OP_NO_SSLv3 (за исключением PROTOCOL_SSLv3). Исходный список наборов шифров содержит только HIGH шифры, без NULL шифров и без MD5 шифров (за исключением PROTOCOL_SSLv2).

Объекты SSLContext имеют следующие методы и атрибуты:

SSLContext.cert_store_stats()

Возвращает статистику в виде словаря: количество загруженных X.509-сертификатов, количество сертификатов X.509, помеченных как CA-сертификаты, и списки отзыва сертификатов.

Пример для контекста с одним CA-сертификатом и одним обычным сертификатом:

python
>>> context.cert_store_stats()
{'crl': 0, 'x509_ca': 1, 'x509': 2}

Новое в версии 3.4.

SSLContext.load_cert_chain(certfile, keyfile=None, password=None)

Загружает закрытый ключ и соответствующий сертификат. Строка certfile должна быть путём к единственному файлу в формате PEM, содержащему сертификат, а также любое количество сертификатов ЦС, необходимых для подтверждения подлинности сертификата. Строка keyfile, если указана, должна указывать на файл, содержащий закрытый ключ. В противном случае закрытый ключ также будет взят из certfile. См. обсуждение Certificates для получения дополнительной информации о том, как сертификат хранится в certfile.

Аргумент password может быть функцией, вызываемой для получения пароля для расшифровки закрытого ключа. Она будет вызвана только в том случае, если закрытый ключ зашифрован и требуется пароль. Функция вызывается без аргументов и должна возвращать строку, bytes или bytearray. Если возвращаемое значение – строка, она будет закодирована в UTF-8 перед использованием для расшифровки ключа. В качестве аргумента password можно также передать непосредственно строку, bytes или bytearray. Этот аргумент будет проигнорирован, если закрытый ключ не зашифрован и пароль не требуется.

Если аргумент password не указан, а пароль требуется, будет использован встроенный механизм запроса пароля OpenSSL для интерактивного запроса пароля у пользователя.

Возникает SSLError, если закрытый ключ не соответствует сертификату.

Изменено в версии 3.3: Новый опциональный аргумент password.

SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)

Загружает набор стандартных сертификатов «удостоверяющего центра» (ЦС) из расположений по умолчанию. В Windows загружает сертификаты ЦС из системных хранилищ CA и ROOT. В других системах вызывает SSLContext.set_default_verify_paths(). В будущем метод может также загружать сертификаты ЦС из других расположений.

Флаг purpose определяет, какие именно CA-сертификаты загружаются. Настройка по умолчанию Purpose.SERVER_AUTH загружает сертификаты, помеченные как доверенные для TLS-аутентификации веб-сервера (клиентские сокеты). А Purpose.CLIENT_AUTH загружает CA-сертификаты для проверки сертификата клиента на стороне сервера.

Новое в версии 3.4.

SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)

Загружает набор сертификатов «удостоверяющего центра» (CA), используемых для проверки сертификатов других сторон, когда verify_mode отличен от CERT_NONE. Должен быть указан хотя бы один из параметров cafile или capath.

Этот метод также может загружать списки отзыва сертификатов (CRL) в формате PEM или DER. Для использования CRL необходимо правильно настроить SSLContext.verify_flags.

Строка cafile, если указана, – это путь к файлу, содержащему объединённые CA-сертификаты в формате PEM. Дополнительную информацию о том, как организовать сертификаты в этом файле, см. в обсуждении Certificates.

Строка capath, если указана, – это путь к каталогу, содержащему несколько CA-сертификатов в формате PEM, с организацией согласно специфической структуре OpenSSL.

Объект cadata, если указан, представляет собой либо ASCII-строку с одним или несколькими PEM-кодированными сертификатами, либо bytes-подобный объект с DER-кодированными сертификатами. Как и в случае с capath, лишние строки вокруг PEM-сертификатов игнорируются, но должен присутствовать хотя бы один сертификат.

Изменено в версии 3.4: Новый опциональный аргумент cadata.

SSLContext.get_ca_certs(binary_form=False)

Возвращает список загруженных сертификатов «удостоверяющего центра» (CA). Если параметр binary_form равен False, каждый элемент списка представляет собой словарь, как в выводе SSLSocket.getpeercert(). В противном случае метод возвращает список DER-кодированных сертификатов. Возвращаемый список не содержит сертификаты из capath, если только сертификат не был запрошен и загружен через SSL-соединение.

Примечание

Сертификаты в каталоге capath не загружаются, пока не будут использованы хотя бы один раз.

Новое в версии 3.4.

SSLContext.get_ciphers()

Возвращает список включённых шифров. Список отсортирован по приоритету шифров. См. SSLContext.set_ciphers().

Пример:

python
>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
>>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
>>> ctx.get_ciphers()  # OpenSSL 1.0.x
[{'alg_bits': 256,
  'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(256) Mac=AEAD',
  'id': 50380848,
  'name': 'ECDHE-RSA-AES256-GCM-SHA384',
  'protocol': 'TLSv1/SSLv3',
  'strength_bits': 256},
 {'alg_bits': 128,
  'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(128) Mac=AEAD',
  'id': 50380847,
  'name': 'ECDHE-RSA-AES128-GCM-SHA256',
  'protocol': 'TLSv1/SSLv3',
  'strength_bits': 128}]
В OpenSSL 1.1 и новее словарь шифров содержит дополнительные поля::
text
>>> ctx.get_ciphers()  # OpenSSL 1.1+
[{'aead': True,
  'alg_bits': 256,
  'auth': 'auth-rsa',
  'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(256) Mac=AEAD',
  'digest': None,
  'id': 50380848,
  'kea': 'kx-ecdhe',
  'name': 'ECDHE-RSA-AES256-GCM-SHA384',
  'protocol': 'TLSv1.2',
  'strength_bits': 256,
  'symmetric': 'aes-256-gcm'},
 {'aead': True,
  'alg_bits': 128,
  'auth': 'auth-rsa',
  'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(128) Mac=AEAD',
  'digest': None,
  'id': 50380847,
  'kea': 'kx-ecdhe',
  'name': 'ECDHE-RSA-AES128-GCM-SHA256',
  'protocol': 'TLSv1.2',
  'strength_bits': 128,
  'symmetric': 'aes-128-gcm'}]

Доступно: OpenSSL 1.0.2+

Новое в версии 3.6.

SSLContext.set_default_verify_paths()

Загружает набор сертификатов по умолчанию «центра сертификации» (CA) из пути файловой системы, заданного при сборке библиотеки OpenSSL. К сожалению, не существует простого способа узнать, успешна ли эта операция: об ошибке не сообщается, если сертификаты не найдены. Если же библиотека OpenSSL поставляется как часть операционной системы, она, скорее всего, настроена правильно.

SSLContext.set_ciphers(ciphers)

Устанавливает доступные шифры для сокетов, созданных с этим контекстом. Она должна быть строкой в формате списка шифров OpenSSL. Если не удаётся выбрать ни один шифр (например, из-за опций компиляции или других настроек, запрещающих использование всех указанных шифров), будет вызвано исключение SSLError.

Примечание

при подключении метод SSLSocket.cipher() SSL-сокетов возвращает текущий выбранный шифр.

В OpenSSL 1.1.1 наборы шифров TLS 1.3 включены по умолчанию. Эти наборы не могут быть отключены с помощью set_ciphers().

SSLContext.set_alpn_protocols(protocols)

Указывает, какие протоколы сокет должен объявлять во время рукопожатия SSL/TLS. Это должен быть список ASCII-строк, например ['http/1.1', 'spdy/2'], упорядоченный по предпочтению. Выбор протокола произойдет во время рукопожатия в соответствии с RFC 7301. После успешного рукопожатия метод SSLSocket.selected_alpn_protocol() вернёт согласованный протокол.

Этот метод вызывает NotImplementedError, если HAS_ALPN равно False.

OpenSSL 1.1.0 – 1.1.0e прерывает рукопожатие и вызывает SSLError когда обе стороны поддерживают ALPN, но не могут согласовать протокол. Начиная с 1.1.0f поведение аналогично 1.0.2: SSLSocket.selected_alpn_protocol() возвращает None.

Новое в версии 3.5.

SSLContext.set_npn_protocols(protocols)

Укажите, какие протоколы сокет должен объявлять во время рукопожатия SSL/TLS. Это должен быть список строк, например ['http/1.1', 'spdy/2'], упорядоченных по предпочтению. Выбор протокола происходит во время рукопожатия и осуществляется в соответствии с черновиком спецификации NPN. После успешного рукопожатия метод SSLSocket.selected_npn_protocol() вернёт согласованный протокол.

Этот метод вызывает NotImplementedError, если HAS_NPN равно False.

Новое в версии 3.3.

SSLContext.set_servername_callback(server_name_callback)

Регистрирует функцию обратного вызова, которая будет вызвана после того, как сервер SSL/TLS получит сообщение рукопожатия TLS Client Hello, когда клиент TLS указывает указание имени сервера. Механизм указания имени сервера описан в RFC 6066, раздел 3 – Server Name Indication.

На один SSLContext можно установить только один колбэк. Если server_name_callback равно None, то колбэк отключается. Повторный вызов этой функции отключит ранее зарегистрированный колбэк.

Функция обратного вызова server_name_callback будет вызвана с тремя аргументами: первый – это ssl.SSLSocket, второй – строка, представляющая имя сервера, с которым клиент намерен установить связь (или None, если TLS Client Hello не содержит имени сервера), и третий аргумент – исходный SSLContext. Аргумент имени сервера – это имя сервера, декодированное по IDNA.

Типичное применение этого колбэка – изменить атрибут SSLSocket.context объекта ssl.SSLSocket на новый объект типа SSLContext, представляющий цепочку сертификатов, соответствующую имени сервера.

Из-за ранней фазы согласования TLS-соединения доступны лишь ограниченные методы и атрибуты, такие как SSLSocket.selected_alpn_protocol() и SSLSocket.context. Методы SSLSocket.getpeercert(), SSLSocket.getpeercert(), SSLSocket.cipher() и SSLSocket.compress() требуют, чтобы TLS-соединение продвинулось дальше TLS Client Hello, и поэтому не будут возвращать осмысленных значений и не могут быть безопасно вызваны.

Функция server_name_callback должна возвращать None, чтобы продолжить согласование TLS. Если требуется ошибка TLS, можно вернуть константу ALERT_DESCRIPTION_*. Другие возвращаемые значения приведут к фатальной ошибке TLS с ALERT_DESCRIPTION_INTERNAL_ERROR.

Если при декодировании IDNA имени сервера возникает ошибка, TLS-соединение завершится отправкой клиенту фатального предупреждающего сообщения TLS с кодом ALERT_DESCRIPTION_INTERNAL_ERROR.

Если из функции server_name_callback будет возбуждено исключение, TLS-соединение завершится фатальным предупреждающим сообщением TLS ALERT_DESCRIPTION_HANDSHAKE_FAILURE.

Этот метод вызовет NotImplementedError, если библиотека OpenSSL была собрана с определённым OPENSSL_NO_TLSEXT.

Новое в версии 3.4.

SSLContext.load_dh_params(dhfile)

Загружает параметры генерации ключей для обмена ключами Диффи-Хеллмана (DH). Использование обмена ключами DH повышает прямую секретность ценой вычислительных ресурсов (как на сервере, так и на клиенте). Параметр dhfile должен быть путём к файлу, содержащему параметры DH в формате PEM.

Этот параметр не применяется к клиентским сокетам. Для дальнейшего повышения безопасности можно также использовать опцию OP_SINGLE_DH_USE.

Новое в версии 3.3.

SSLContext.set_ecdh_curve(curve_name)

Устанавливает имя кривой для обмена ключами на основе эллиптических кривых (ECDH). ECDH значительно быстрее обычного DH, при этом, возможно, столь же безопасен. Параметр curve_name должен быть строкой, описывающей известную эллиптическую кривую, например prime256v1 для широко поддерживаемой кривой.

Этот параметр не применяется к клиентским сокетам. Для дальнейшего повышения безопасности можно также использовать опцию OP_SINGLE_ECDH_USE.

Этот метод недоступен, если HAS_ECDH равно False.

Новое в версии 3.3.

SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)

Оборачивает существующий сокет Python sock и возвращает объект SSLSocket. Сокет sock должен быть сокетом SOCK_STREAM; другие типы сокетов не поддерживаются.

Возвращаемый SSL-сокет привязан к контексту, его настройкам и сертификатам. Параметры server_side, do_handshake_on_connect и suppress_ragged_eofs имеют тот же смысл, что и в функции верхнего уровня wrap_socket().

При клиентских подключениях необязательный параметр server_hostname задаёт имя хоста службы, к которой выполняется подключение. Это позволяет одному серверу размещать несколько служб на основе SSL с различными сертификатами, примерно как виртуальные хосты HTTP. Указание server_hostname вызовет ValueError, если server_side равно true.

session, см. session.

Изменено в версии 3.5: Всегда разрешается передавать server_hostname, даже если OpenSSL не поддерживает SNI.

Изменено в версии 3.6: Добавлен аргумент session.

SSLContext.wrap_bio(incoming, outgoing, server_side=False, server_hostname=None, session=None)

Создаёт новый экземпляр SSLObject, оборачивая BIO-объекты incoming и outgoing. Процедуры SSL будут читать входные данные из входящего BIO и записывать данные в исходящий BIO.

Параметры server_side, server_hostname и session имеют тот же смысл, что и в SSLContext.wrap_socket().

Изменено в версии 3.6: Добавлен аргумент session.

SSLContext.session_stats()

Возвращает статистику по SSL-сессиям, созданным или управляемым этим контекстом. Возвращается словарь, который сопоставляет названия каждого элемента информации с их числовыми значениями. Например, вот общее количество попаданий и промахов в кеше сессий с момента создания контекста:

python
>>> stats = context.session_stats()
>>> stats['hits'], stats['misses']
(0, 0)
SSLContext.check_hostname

Указывает, следует ли сопоставлять имя хоста сертификата партнёра с match_hostname() в SSLSocket.do_handshake(). Параметр verify_mode контекста должен быть установлен в CERT_OPTIONAL или CERT_REQUIRED, и необходимо передать server_hostname в wrap_socket(), чтобы сопоставить имя хоста.

Пример:

python
import socket, ssl

context = ssl.SSLContext()
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_default_certs()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com')
ssl_sock.connect(('www.verisign.com', 443))

Новое в версии 3.4.

Примечание

Для этой функции требуется OpenSSL 0.9.8f или новее.

SSLContext.options

Целое число, представляющее набор опций SSL, включённых в этом контексте. Значение по умолчанию – OP_ALL, но можно указать другие опции, такие как OP_NO_SSLv2, объединяя их через OR.

Примечание

В версиях OpenSSL старше 0.9.8m можно только установить параметры, но не сбросить их. Попытка сбросить параметр (сбросив соответствующие биты) вызовет ValueError.

Изменено в версии 3.6: SSLContext.options возвращает Options флаги:

text
>>> ssl.create_default_context().options
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
SSLContext.post_handshake_auth

Включает аутентификацию клиента после рукопожатия TLS 1.3. Аутентификация после рукопожатия по умолчанию отключена, и сервер может запрашивать сертификат клиента только во время начального рукопожатия. При включении сервер может запросить сертификат клиента в любое время после рукопожатия.

При включении на стороне клиента сокет клиента сообщает серверу, что он поддерживает аутентификацию после рукопожатия.

При включении на стороне сервера SSLContext.verify_mode также должен быть установлен в CERT_OPTIONAL или CERT_REQUIRED. Фактический обмен сертификатом клиента откладывается до вызова SSLSocket.verify_client_post_handshake() и выполнения некоторого ввода-вывода.

Новое в версии 3.6.7.

Примечание

Доступно только с OpenSSL 1.1.1 и включённым TLS 1.3. Без поддержки TLS 1.3 значение свойства равно None и не может быть изменено.

SSLContext.protocol

Версия протокола, выбранная при создании контекста. Этот атрибут доступен только для чтения.

SSLContext.verify_flags

Флаги операций проверки сертификатов. Вы можете установить флаги, например VERIFY_CRL_CHECK_LEAF, скомбинировав их через OR. По умолчанию OpenSSL не требует и не проверяет списки отзыва сертификатов (CRL). Доступно только с openssl version 0.9.8+.

Новое в версии 3.4.

Изменено в версии 3.6: SSLContext.verify_flags возвращает VerifyFlags флаги:

text
>>> ssl.create_default_context().verify_flags
<VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
SSLContext.verify_mode

Определяет, следует ли пытаться проверять сертификаты других участников соединения и как вести себя при неудачной проверке. Этот атрибут должен быть одним из CERT_NONE, CERT_OPTIONAL или CERT_REQUIRED.

Изменено в версии 3.6: SSLContext.verify_mode возвращает VerifyMode перечисление:

text
>>> ssl.create_default_context().verify_mode
<VerifyMode.CERT_REQUIRED: 2>

18.2.4. Сертификаты

Сертификаты в целом являются частью системы с открытым и закрытым ключами. В этой системе каждому субъекту (которым может быть машина, человек или организация) назначается уникальный двухкомпонентный ключ шифрования. Одна часть ключа является открытой и называется открытым ключом; другая часть хранится в секрете и называется закрытым ключом. Эти две части связаны таким образом, что если зашифровать сообщение одной частью, то расшифровать его можно только другой частью, и только другой частью.

Сертификат содержит информацию о двух субъектах. Он содержит имя субъекта и его открытый ключ. Также он содержит заявление второго субъекта – издателя, о том, что субъект действительно тот, за кого себя выдает, и что это действительно его открытый ключ. Заявление издателя подписано закрытым ключом издателя, который известен только издателю. Однако любой может проверить заявление издателя, найдя его открытый ключ, расшифровав заявление с его помощью и сравнив с другой информацией в сертификате. Сертификат также содержит информацию о периоде действия, которая выражается двумя полями: “notBefore” и “notAfter”.

При использовании сертификатов в Python клиент или сервер могут использовать сертификат для подтверждения своей подлинности. Другая сторона сетевого соединения также может быть обязана предоставить сертификат, и этот сертификат может быть проверен с удовлетворением требований клиента или сервера, запрашивающего такую проверку. При попытке соединения можно настроить вызов исключения в случае неудачной проверки. Проверка выполняется автоматически встроенным фреймворком OpenSSL; приложению не нужно вникать в её механику. Однако приложение обычно должно предоставлять наборы сертификатов, чтобы этот процесс мог состояться.

Python использует файлы для хранения сертификатов. Они должны быть отформатированы как “PEM” (см. RFC 1422), что представляет собой форму кодирования base-64, заключенную между строкой заголовка и строкой нижнего колонтитула:

python
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

18.2.4.1. Цепочки сертификатов

Файлы Python, содержащие сертификаты, могут содержать последовательность сертификатов, иногда называемую цепочкой сертификатов. Эта цепочка должна начинаться с сертификата субъекта, который является клиентом или сервером, затем сертификат издателя этого сертификата, затем сертификат издателя этого сертификата и так далее по цепочке, пока не будет достигнут сертификат, который является самоподписанным, то есть сертификат, у которого субъект и издатель совпадают, иногда называемый корневым сертификатом. Сертификаты должны быть просто объединены друг за другом в файле сертификатов. Например, предположим, у нас есть цепочка из трех сертификатов: от сертификата нашего сервера до сертификата удостоверяющего центра, подписавшего наш серверный сертификат, и до корневого сертификата агентства, выпустившего сертификат удостоверяющего центра:

python
-----BEGIN CERTIFICATE-----
... (certificate for your server)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the certificate for the CA)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the root certificate for the CA's issuer)...
-----END CERTIFICATE-----

18.2.4.2. Сертификаты УЦ

Для проверки сертификата другой стороны соединения необходимо предоставить файл “CA certs”, заполненный цепочками сертификатов для каждого издателя, которому вы готовы доверять. Опять же, этот файл просто содержит эти цепочки, объединенные вместе. Для проверки Python будет использовать первую найденную в файле подходящую цепочку. Файл сертификатов платформы можно использовать, вызвав SSLContext.load_default_certs(); это делается автоматически с помощью create_default_context().

18.2.4.3. Объединённые ключ и сертификат

Часто закрытый ключ хранится в том же файле, что и сертификат; в этом случае достаточно передать только параметр certfile в SSLContext.load_cert_chain() и wrap_socket(). Если закрытый ключ хранится вместе с сертификатом, он должен располагаться перед первым сертификатом в цепочке сертификатов:

python
-----BEGIN RSA PRIVATE KEY-----
... (private key in base64 encoding) ...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

18.2.4.4. Самоподписанные сертификаты

Если вы собираетесь создать сервер, предоставляющий услуги SSL-шифрованного соединения, вам потребуется получить сертификат для этой службы. Существует множество способов получения подходящих сертификатов, например, покупка у центра сертификации. Другой распространённой практикой является генерация самоподписанного сертификата. Самый простой способ сделать это – использовать пакет OpenSSL, например, следующим образом:

python
% openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
Generating a 1024 bit RSA private key
.......++++++
.............................++++++
writing new private key to 'cert.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MyState
Locality Name (eg, city) []:Some City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc.
Organizational Unit Name (eg, section) []:My Group
Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com
Email Address []:ops@myserver.mygroup.myorganization.com
%

Недостаток самоподписанного сертификата заключается в том, что он является собственным корневым сертификатом, и никто другой не будет иметь его в кэше известных (и доверенных) корневых сертификатов.

18.2.5. Примеры

18.2.5.1. Проверка поддержки SSL

Для проверки наличия поддержки SSL в установке Python пользовательский код должен использовать следующий идиоматический приём:

python
try:
    import ssl
except ImportError:
    pass
else:
    ...  # выполнить действие, требующее поддержки SSL

18.2.5.2. Работа на стороне клиента

Этот пример создаёт контекст SSL с рекомендуемыми настройками безопасности для клиентских сокетов, включая автоматическую проверку сертификата:

python
>>> context = ssl.create_default_context()

Если вы предпочитаете настраивать параметры безопасности самостоятельно, вы можете создать контекст с нуля (но учтите, что вы можете не получить правильные настройки):

python
>>> context = ssl.SSLContext()
>>> context.verify_mode = ssl.CERT_REQUIRED
>>> context.check_hostname = True
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")

(этот фрагмент предполагает, что ваша операционная система помещает набор всех сертификатов ЦС в /etc/ssl/certs/ca-bundle.crt; если нет, вы получите ошибку и вам придётся изменить расположение)

При использовании контекста для подключения к серверу CERT_REQUIRED проверяет сертификат сервера: он гарантирует, что сертификат сервера был подписан одним из сертификатов УЦ, и проверяет корректность подписи:

python
>>> conn = context.wrap_socket(socket.socket(socket.AF_INET),
...                            server_hostname="www.python.org")
>>> conn.connect(("www.python.org", 443))

Затем вы можете получить сертификат:

python
>>> cert = conn.getpeercert()

Визуальный осмотр показывает, что сертификат действительно идентифицирует нужную службу (то есть HTTPS-хост www.python.org):

python
>>> pprint.pprint(cert)
{'OCSP': ('http://ocsp.digicert.com',),
 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',),
 'crlDistributionPoints': ('http://crl3.digicert.com/sha2-ev-server-g1.crl',
                           'http://crl4.digicert.com/sha2-ev-server-g1.crl'),
 'issuer': ((('countryName', 'US'),),
            (('organizationName', 'DigiCert Inc'),),
            (('organizationalUnitName', 'www.digicert.com'),),
            (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),)),
 'notAfter': 'Sep  9 12:00:00 2016 GMT',
 'notBefore': 'Sep  5 00:00:00 2014 GMT',
 'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26',
 'subject': ((('businessCategory', 'Private Organization'),),
             (('1.3.6.1.4.1.311.60.2.1.3', 'US'),),
             (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),),
             (('serialNumber', '3359300'),),
             (('streetAddress', '16 Allen Rd'),),
             (('postalCode', '03894-4801'),),
             (('countryName', 'US'),),
             (('stateOrProvinceName', 'NH'),),
             (('localityName', 'Wolfeboro,'),),
             (('organizationName', 'Python Software Foundation'),),
             (('commonName', 'www.python.org'),)),
 'subjectAltName': (('DNS', 'www.python.org'),
                    ('DNS', 'python.org'),
                    ('DNS', 'pypi.org'),
                    ('DNS', 'docs.python.org'),
                    ('DNS', 'testpypi.org'),
                    ('DNS', 'bugs.python.org'),
                    ('DNS', 'wiki.python.org'),
                    ('DNS', 'hg.python.org'),
                    ('DNS', 'mail.python.org'),
                    ('DNS', 'packaging.python.org'),
                    ('DNS', 'pythonhosted.org'),
                    ('DNS', 'www.pythonhosted.org'),
                    ('DNS', 'test.pythonhosted.org'),
                    ('DNS', 'us.pycon.org'),
                    ('DNS', 'id.python.org')),
 'version': 3}

Теперь, когда SSL-канал установлен и сертификат проверен, вы можете продолжить общение с сервером:

python
>>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
>>> pprint.pprint(conn.recv(1024).split(b"\r\n"))
[b'HTTP/1.1 200 OK',
 b'Date: Sat, 18 Oct 2014 18:27:20 GMT',
 b'Server: nginx',
 b'Content-Type: text/html; charset=utf-8',
 b'X-Frame-Options: SAMEORIGIN',
 b'Content-Length: 45679',
 b'Accept-Ranges: bytes',
 b'Via: 1.1 varnish',
 b'Age: 2188',
 b'X-Served-By: cache-lcy1134-LCY',
 b'X-Cache: HIT',
 b'X-Cache-Hits: 11',
 b'Vary: Cookie',
 b'Strict-Transport-Security: max-age=63072000; includeSubDomains',
 b'Connection: close',
 b'',
 b'']

Смотрите обсуждение Вопросов безопасности ниже.

18.2.5.3. Операция на стороне сервера

Для работы сервера обычно требуется иметь сертификат сервера и закрытый ключ, каждый в отдельном файле. Сначала вы создадите контекст, содержащий ключ и сертификат, чтобы клиенты могли проверить вашу подлинность. Затем вы откроете сокет, привяжете его к порту, вызовете на нём listen() и начнёте ожидать подключения клиентов:

python
import socket, ssl

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")

bindsocket = socket.socket()
bindsocket.bind(('myaddr.mydomain.com', 10023))
bindsocket.listen(5)

Когда клиент подключается, вы вызовете accept() на сокете, чтобы получить новый сокет с другого конца, и используете метод контекста SSLContext.wrap_socket() для создания серверного SSL-сокета для подключения:

python
while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        deal_with_client(connstream)
    finally:
        connstream.shutdown(socket.SHUT_RDWR)
        connstream.close()

Затем вы будете читать данные из connstream и что-то с ними делать, пока не закончите работу с клиентом (или клиент не закончит с вами):

python
def deal_with_client(connstream):
    data = connstream.recv(1024)
    # пустые данные означают, что клиент закончил работу с нами
    while data:
        if not do_something(connstream, data):
            # будем считать, что do_something возвращает False
            # когда мы закончили с клиентом
            break
        data = connstream.recv(1024)
    # закончили с клиентом

И вернуться к прослушиванию новых клиентских подключений (конечно, настоящий сервер, вероятно, обрабатывал бы каждое клиентское подключение в отдельном потоке или переводил бы сокеты в неблокирующий режим и использовал цикл событий).

18.2.6. Замечания по неблокирующим сокетам

SSL-сокеты ведут себя несколько иначе, чем обычные сокеты в неблокирующем режиме. При работе с неблокирующими сокетами необходимо учитывать несколько моментов:

  • Большинство методов SSLSocket будут вызывать либо SSLWantWriteError, либо SSLWantReadError вместо BlockingIOError, если операция ввода-вывода должна заблокироваться. SSLWantReadError будет вызвано, если необходима операция чтения из нижележащего сокета, а SSLWantWriteError – для операции записи в нижележащий сокет. Обратите внимание, что попытки записи в SSL-сокет могут сначала потребовать чтения из нижележащего сокета, а попытки чтения из SSL-сокета могут потребовать предварительной записи в нижележащий сокет.

    Изменено в версии 3.5: В более ранних версиях Python метод SSLSocket.send() возвращал ноль вместо вызова SSLWantWriteError или SSLWantReadError.

  • Вызов select() сообщает вам, что сокет на уровне ОС может быть прочитан (или записан), но это не означает, что на верхнем уровне SSL достаточно данных. Например, может прибыть только часть SSL-фрейма. Поэтому вы должны быть готовы обрабатывать ошибки SSLSocket.recv() и SSLSocket.send() и повторить попытку после очередного вызова select().

  • И наоборот, поскольку уровень SSL имеет собственную фреймовую структуру, SSL-сокет может всё ещё иметь данные, доступные для чтения, даже если select() не знает об этом. Поэтому сначала следует вызвать SSLSocket.recv(), чтобы получить все потенциально доступные данные, и затем блокироваться на вызове select() только при необходимости.

    (конечно, аналогичные меры применяются при использовании других примитивов, таких как poll() или тех, что в модуле selectors)

  • Само рукопожатие SSL будет неблокирующим: метод SSLSocket.do_handshake() должен повторяться до тех пор, пока он не вернёт успешный результат. Вот краткое описание с использованием select() для ожидания готовности сокета:

    python
    while True:
        try:
            sock.do_handshake()
            break
        except ssl.SSLWantReadError:
            select.select([sock], [], [])
        except ssl.SSLWantWriteError:
            select.select([], [sock], [])
    

Смотрите также

Модуль asyncio поддерживает неблокирующие SSL-сокеты и предоставляет API более высокого уровня. Он опрашивает события с помощью модуля selectors и обрабатывает исключения SSLWantWriteError, SSLWantReadError и BlockingIOError. Кроме того, он выполняет SSL-рукопожатие асинхронно.

18.2.7. Поддержка Memory BIO

Новое в версии 3.5.

С момента появления модуля SSL в Python 2.6 класс SSLSocket предоставляет две связанные, но различные области функциональности:

  • Обработка протокола SSL

  • Сетевой ввод-вывод

API сетевого ввода-вывода идентичен тому, который предоставляется socket.socket, от которого также наследует SSLSocket. Это позволяет использовать SSL-сокет как прямую замену обычного сокета, что значительно упрощает добавление поддержки SSL в существующее приложение.

Объединение обработки протокола SSL и сетевого ввода-вывода обычно работает хорошо, но есть случаи, когда это не так. Примером являются асинхронные фреймворки ввода-вывода, которые хотят использовать другую модель мультиплексирования IO, отличную от модели «select/poll на файловом дескрипторе» (основанной на готовности), которая предполагается socket.socket и внутренними процедурами сокетного IO OpenSSL. Это в основном актуально для таких платформ, как Windows, где эта модель неэффективна. Для этой цели предоставляется вариант SSLSocket с ограниченной областью применения, называемый SSLObject.

classssl.SSLObject

Вариант SSLSocket с ограниченной областью применения, представляющий экземпляр протокола SSL, который не содержит методов сетевого ввода-вывода. Этот класс обычно используется разработчиками фреймворков, которые хотят реализовать асинхронный ввод-вывод для SSL через буферы памяти.

Этот класс реализует интерфейс поверх низкоуровневого SSL-объекта, реализованного OpenSSL. Этот объект хранит состояние SSL-соединения, но сам не предоставляет никакого сетевого ввода-вывода. Ввод-вывод должен выполняться через отдельные объекты «BIO», которые являются уровнем абстракции ввода-вывода OpenSSL.

Экземпляр SSLObject можно создать с помощью метода wrap_bio(). Этот метод создаст экземпляр SSLObject и привяжет его к паре BIO. Входящий BIO используется для передачи данных из Python в экземпляр протокола SSL, а исходящий BIO – для передачи данных в обратном направлении.

Доступны следующие методы:

По сравнению с SSLSocket, у этого объекта отсутствуют следующие возможности:

  • Любая форма сетевого ввода-вывода; recv() и send() читают и записывают данные только в базовые буферы MemoryBIO.

  • Отсутствует механизм do_handshake_on_connect. Необходимо всегда вручную вызывать do_handshake(), чтобы начать рукопожатие.

  • Отсутствует обработка suppress_ragged_eofs. Все ситуации конца файла, нарушающие протокол, сообщаются через исключение SSLEOFError.

  • Вызов метода unwrap() ничего не возвращает, в отличие от SSL-сокета, где он возвращает базовый сокет.

  • Колбэк server_name_callback, переданный в SSLContext.set_servername_callback(), получит экземпляр SSLObject вместо экземпляра SSLSocket в качестве первого параметра.

Некоторые замечания, касающиеся использования SSLObject:

  • Весь ввод-вывод на SSLObject является неблокирующим. Это означает, что, например, read() вызовет исключение SSLWantReadError, если ему потребуется больше данных, чем есть во входящем BIO.

  • Не существует вызова wrap_bio() на уровне модуля, как для wrap_socket(). SSLObject всегда создается через SSLContext.

SSLObject взаимодействует с внешним миром, используя буферы памяти. Класс MemoryBIO предоставляет буфер памяти, который можно использовать для этой цели. Он оборачивает объект OpenSSL memory BIO (базовый ввод-вывод):

classssl.MemoryBIO

Буфер памяти, который можно использовать для передачи данных между Python и экземпляром протокола SSL.

pending

Возвращает количество байтов, находящихся в данный момент в буфере памяти.

eof

Логическое значение, указывающее, находится ли memory BIO в текущий момент в позиции конца файла.

read(n=-1)

Читает до n байтов из буфера памяти. Если n не указан или отрицателен, возвращаются все байты.

write(buf)

Записывает байты из buf в memory BIO. Аргумент buf должен быть объектом, поддерживающим буферный протокол.

Возвращаемое значение – количество записанных байтов, которое всегда равно длине buf.

write_eof()

Записывает маркер EOF в memory BIO. После вызова этого метода запрещено вызывать write(). Атрибут eof станет истинным после того, как все данные, находящиеся в буфере, будут прочитаны.

18.2.8. Сессия SSL

Новое в версии 3.6.

classssl.SSLSession

Объект сессии, используемый session.

id
time
timeout
ticket_lifetime_hint
has_ticket

18.2.9. Вопросы безопасности

18.2.9.1. Рекомендуемые настройки по умолчанию

Для использования на стороне клиента, если у вас нет особых требований к политике безопасности, настоятельно рекомендуется использовать функцию create_default_context() для создания SSL-контекста. Она загрузит доверенные сертификаты ЦС вашей системы, включит проверку сертификатов и имени хоста, а также попытается выбрать достаточно безопасные настройки протокола и шифров.

Например, вот как можно использовать класс smtplib.SMTP для создания доверенного безопасного соединения с SMTP-сервером:

python
>>> import ssl, smtplib
>>> smtp = smtplib.SMTP("mail.python.org", port=587)
>>> context = ssl.create_default_context()
>>> smtp.starttls(context=context)
(220, b'2.0.0 Ready to start TLS')

Если для соединения требуется клиентский сертификат, его можно добавить с помощью SSLContext.load_cert_chain().

Напротив, если вы создаёте SSL-контекст, вызывая конструктор SSLContext самостоятельно, по умолчанию в нём не будут включены проверка сертификатов и проверка имени хоста. Если вы так делаете, пожалуйста, прочитайте следующие абзацы, чтобы достичь хорошего уровня безопасности.

18.2.9.2. Ручные настройки

18.2.9.2.1. Проверка сертификатов

При прямом вызове конструктора SSLContext по умолчанию используется CERT_NONE. Поскольку он не аутентифицирует другую сторону, это может быть небезопасно, особенно в клиентском режиме, где в большинстве случаев требуется убедиться в подлинности сервера, с которым ведется обмен. Поэтому в клиентском режиме настоятельно рекомендуется использовать CERT_REQUIRED. Однако только этого недостаточно; необходимо также проверить, что сертификат сервера, который можно получить с помощью SSLSocket.getpeercert(), соответствует требуемой службе. Для многих протоколов и приложений службу можно идентифицировать по имени хоста; в этом случае можно использовать функцию match_hostname(). Эта проверка выполняется автоматически, если включено SSLContext.check_hostname.

В серверном режиме, если вы хотите аутентифицировать клиентов с помощью уровня SSL (а не использовать механизм аутентификации более высокого уровня), вам также придётся указать CERT_REQUIRED и аналогично проверить клиентский сертификат.

18.2.9.2.2. Версии протоколов

Версии SSL 2 и 3 считаются небезопасными, и поэтому их опасно использовать. Если вы хотите максимальной совместимости между клиентами и серверами, рекомендуется использовать PROTOCOL_TLS_CLIENT или PROTOCOL_TLS_SERVER в качестве версии протокола. SSLv2 и SSLv3 отключены по умолчанию.

text
>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> client_context.options |= ssl.OP_NO_TLSv1
>>> client_context.options |= ssl.OP_NO_TLSv1_1

Созданный выше контекст SSL будет разрешать соединения с сервером только по протоколу TLSv1.2 и новее (если поддерживается системой). PROTOCOL_TLS_CLIENT подразумевает проверку сертификата и проверку имени хоста по умолчанию. Необходимо загрузить сертификаты в контекст.

18.2.9.2.3. Выбор шифров

Если у вас повышенные требования к безопасности, тонкая настройка шифров, доступных при согласовании SSL-сессии, возможна через метод SSLContext.set_ciphers(). Начиная с Python 3.2.3 модуль ssl отключает некоторые слабые шифры по умолчанию, но вы можете дополнительно ограничить выбор шифров. Обязательно прочитайте документацию OpenSSL о формате списка шифров. Если вы хотите проверить, какие шифры включены для данного списка шифров, используйте SSLContext.get_ciphers() или команду openssl ciphers в вашей системе.

18.2.9.3. Многопроцессность

При использовании этого модуля в многопроцессном приложении (например, с модулями multiprocessing или concurrent.futures) следует учитывать, что внутренний генератор случайных чисел OpenSSL некорректно обрабатывает разветвленные процессы. Приложения должны изменить состояние PRNG родительского процесса, если они используют какие-либо функции SSL с os.fork(). Любого успешного вызова RAND_add(), RAND_bytes() или RAND_pseudo_bytes() достаточно.

18.2.10. Поддержка LibreSSL

LibreSSL – это форк OpenSSL 1.0.1. Модуль ssl имеет ограниченную поддержку LibreSSL. Некоторые функции недоступны, когда модуль ssl скомпилирован с LibreSSL.