Поддержка SSL
В QHB имеется встроенная поддержка применения SSL-подключений для шифрования клиент-серверного взаимодействия в целях укрепления безопасности. Подробную информацию о функциональности SSL на стороне сервера см. в разделе Защита TCP/IP-соединений посредством SSL.
libpq читает общесистемный файл конфигурации OpenSSL. По умолчанию этот файл
называется openssl.cnf и располагается в каталоге, выводимом командой
openssl version -d
. Эти стандартные значения можно переопределить, установив в
переменной среды OPENSSL_CONF имя желаемого файла конфигурации.
Проверка сертификатов сервера на стороне клиента
По умолчанию QHB не будет выполнять никакую проверку сертификата сервера. Это означает, что можно без ведома клиента имитировать подлинность сервера (например, модифицировав запись в DNS или заняв его IP-адрес). Чтобы предотвратить подмену, клиент должен иметь возможность проверить подлинность сервера посредством цепочки доверия. Цепочка доверия устанавливается путем размещения корневого (самоподписанного) сертификата центра сертификации (CA) на одном компьютере и конечного сертификата, подписанного корневым, на другом. Также можно использовать «промежуточный» сертификат, который подписывается корневым сертификатом и подписывает конечные сертификаты.
Чтобы позволить клиенту проверить подлинность сервера, разместите на клиенте корневой сертификат, а на сервере — конечный, подписанный этим корневым. Чтобы позволить серверу проверить подлинность клиента, разместите на сервере корневой сертификат, а на клиенте — конечный, подписанный этим корневым. Кроме того, чтобы связать конечный сертификат с корневым, можно использовать один или несколько промежуточных сертификатов (обычно они хранятся вместе с конечным сертификатом).
После установления цепочки доверия клиент может проверить переданный сервером конечный сертификат двумя способами. Если в параметре sslmode установлено значение verify-ca, libpq будет подтверждать достоверность сервера, проверяя цепочку сертификатов до корневого сертификата, хранящегося на клиенте. Если в sslmode установлено значение verify-full, libpq будет также проверять соответствие имени хоста сервера имени, сохраненному в сертификате сервера. SSL-подключение не будет установлено, если сертификат сервера нельзя проверить. Для большинства сред, требующих повышенной безопасности данных, рекомендуется устанавливать режим verify-full.
В режиме verify-full имя хоста сопоставляется с атрибутом(ами) Subject Alternative Name (Альтернативное имя субъекта, SAN) в сертификате или с атрибутом Common Name (Общее имя), если отсутствует SAN типа dNSName. Если атрибут имени сертификата начинается со звездочки (*), она будет восприниматься как подстановочный знак, которому будут соответствовать все символы, кроме точки (.). Это означает, что сертификат не будет соответствовать поддоменам. Если подключение устанавливается по IP-адресу, а не по имени хоста, этот IP-адрес будет сопоставляться (без поиска в DNS) с SAN типа iPAddress или dNSName. Если SAN типа iPAddress и соответствующее SAN типа dNSName отсутствуют, IP-адрес хоста сопоставляется с атрибутом Common Name.
Примечание
Для обратной совместимости с предыдущими версиями QHB IP-адрес хоста проверяется не совсем так, как того требует RFC 6125. IP-адрес хоста всегда сопоставляется с SAN типа dNSName, а также с SAN типа iPAddress и может сопоставляться с атрибутом Common Name, если подходящей записи SAN не существует.
Чтобы разрешить проверку сертификата сервера, нужно поместить один или несколько корневых сертификатов в файл ~/.qhb/root.crt в домашнем каталоге пользователя. Также следует добавить в этот файл промежуточные сертификаты, если они необходимы для связывания цепочки сертификатов, переданных сервером, с корневыми сертификатами, хранящимися на клиенте.
Если файл ~/.qhb/root.crl существует, также проверяются записи в списке отозванных сертификатов (Certificate Revocation List, CRL).
Расположение файла корневых сертификатов и CRL можно изменить, установив параметры подключения sslrootcert и sslcrl или переменные среды PGSSLROOTCERT и PGSSLCRL. Кроме того, чтобы задать каталог, содержащий файлы CRL, можно воспользоваться параметром sslcrldir или переменной среды PGSSLCRLDIR.
Примечание
Для обратной совместимости с предыдущими версиями QHB, если файл с сертификатами корневых CA существует, поведение режима sslmode=require не будет отличаться от режима verify-ca, то есть сертификат сервера проверяется по сертификату CA. Полагаться на это поведение не рекомендуется, и приложения, которым необходима проверка сертификата, должны всегда применять режим verify-ca или verify-full.
Сертификаты клиента
Если сервер пытается проверить подлинность клиента, запрашивая его конечный сертификат, libpq передаст сертификаты, сохраненные в файле ~/.qhb/qhb.crt в домашнем каталоге пользователя. Эти сертификаты должны связываться по цепочке с корневым сертификатом, которому доверяет сервер. Также должен присутствовать соответствующий файл закрытого ключа ~/.qhb/qhb.key. Расположение файлов сертификатов и ключа можно переопределить с помощью параметров подключения sslcert и sslkey или переменных среды PGSSLCERT и PGSSLKEY.
В системах Unix разрешения для файла закрытого ключа должны запрещать любой
доступ к нему всех или группе; этого можно добиться, например, с помощью команды
chmod 0600 ~/.qhb/qhb.key
. Как вариант, этим файлом может владеть root, а группа
имеет доступ на чтение (то есть маска разрешений 0640). Такая схема предназначена
для установок, где файлами сертификатов и ключа управляет сама операционная
система. При этом пользователь libpq должен быть членом группы, имеющей доступ к
этим файлам сертификатов и ключа.
Первым сертификатом в qhb.crt должен быть сертификат клиента, поскольку он должен соответствовать закрытому ключу клиента. При необходимости в этот файл могут быть добавлены «промежуточные» сертификаты — это позволяет избежать необходимости в хранении промежуточных сертификатов на сервере (ssl_ca_file).
Сертификат и ключ могут задаваться в формате PEM или ASN.1 DER.
Ключ можно хранить в открытом виде или зашифровать паролем, используя любой алгоритм, поддерживаемый OpenSSL, например AES-128. Если ключ хранится зашифрованным, то пароль можно задать в параметре подключения sslpassword. Если предоставляется зашифрованный ключ, а параметр sslpassword отсутствует или имеет пустое значение, пароль будет запрашиваться OpenSSL интерактивно в строке приглашения Enter PEM pass phrase: (введите пароль для PEM:), если имеется TTY. Приложения могут переопределить приглашение на ввод пароля для сертификата клиента и обработку параметра sslpassword, предоставив собственную функцию обратного вызова для пароля ключа; см. PQsetSSLKeyPassHook_OpenSSL.
Инструкции по созданию сертификатов см. в подразделе Создание сертификатов.
Защита, обеспечиваемая в различных режимах
Разные значения параметра sslmode предоставляют разные уровни защиты. SSL может обеспечить защиту от трех типов атак:
Подслушивание
Если третья сторона может просматривать сетевой трафик между клиентом и сервером, она может прочитать как информацию о подключении (включая имя пользователя и пароль), так и передаваемые через него данные. Чтобы предотвратить это, SSL использует шифрование.
Посредник (MITM)
Если третья сторона может модифицировать данные, передаваемые между клиентом и сервером, она может притвориться сервером и, как следствие, видеть и модифицировать данные, даже если они зашифрованы. Затем третья сторона может перенаправлять информацию о подключении и данные оригинальному серверу, делая невозможным обнаружение этой атаки. Распространенные векторы подобных действий включают отравление DNS-сервера и перехват адресов, в результате чего клиент обращается не к тому серверу, к которому намеревался. Также этого можно добиться и некоторыми другими методами атаки. Чтобы предотвратить это, SSL использует проверку сертификатов, чтобы аутентифицировать сервер для клиента.
Подмена
Если третья сторона может притвориться авторизованным клиентом, она может просто обращаться к данным, к которым не должна иметь доступа. Обычно это может произойти вследствие небезопасного управления паролями. Чтобы предотвратить это, SSL использует сертификаты клиента, гарантирующие, что к серверу могут обращаться только владельцы действительных сертификатов.
Чтобы подключение точно было защищено SSL, применение SSL должно быть сконфигурировано и на клиенте, и на сервере до установки подключения. Если оно сконфигурировано только на сервере, клиент может начать передавать конфиденциальную информацию (например, пароли) раньше, чем поймет, что сервер требует высокого уровня безопасности. В libpq безопасные подключения можно обеспечить, установив в параметре sslmode значение verify-full или verify-ca и предоставив системе корневой сертификат для сопоставления при проверке. Это аналогично использованию URL с https для шифрования при просмотре сайтов.
После аутентификации сервера клиент может передавать конфиденциальные данные. Это означает, что до этого момента клиенту не нужно знать, будут ли для аутентификации использоваться сертификаты, поэтому указывать их только в конфигурации сервера будет безопасно.
Все варианты применения SSL несут издержки в форме шифрования и обмена ключами, поэтому необходимо соблюсти баланс между производительностью и безопасностью. В Таблице 1 проиллюстрированы риски, от которых защищают различные режимы sslmode, и приводятся утверждения, касающиеся защиты и издержек.
Таблица 1. Описания режимов SSL
sslmode | Защита от подслушивания | Защита от MITM | Утверждение |
---|---|---|---|
disable | Нет | Нет | Мне не важна безопасность, и я не желаю иметь издержки, связанные с шифрованием. |
allow | Возможно | Нет | Мне не важна безопасность, но я готов иметь издержки, связанные с шифрованием, если на этом настаивает сервер. |
prefer | Возможно | Нет | Мне не важно шифрование, но я согласен иметь издержки, связанные с шифрованием, если это поддерживает сервер. |
require | Да | Нет | Я хочу, чтобы мои данные шифровались, и я приемлю эти издержки. Я доверяю сети в том, что она всегда обеспечит подключение к нужному мне серверу. |
verify-ca | Да | Зависит от политики CA | Я хочу, чтобы мои данные шифровались, и я приемлю эти издержки. Я хочу быть уверенным, что подключаюсь к доверенному серверу. |
verify-full | Да | Да | Я хочу, чтобы мои данные шифровались, и я приемлю эти издержки. Я хочу быть уверенным, что подключаюсь к доверенному серверу и что это тот сервер, который я указал. |
Различие между verify-ca и verify-full зависит от политики корневого CA. Если используется публичный CA, verify-ca допускает подключения к серверу, который в этом CA может зарегистрировать кто угодно. В таком случае нужно всегда использовать режим verify-full. Если используется локальный CA или даже самоподписанный сертификат, режим verify-ca зачастую обеспечивает достаточную защиту.
По умолчанию параметр sslmode имеет значение prefer. Как показано в таблице, этот режим не имеет смысла с точки зрения безопасности и может только приносить издержки производительности. Он выбран по умолчанию для обратной совместимости и не рекомендуется для защищенных развертываний.
Файлы, используемые клиентом SSL
В Таблице 2 приведены файлы, имеющие отношение к настройке SSL на стороне клиента.
Таблица 2. Файлы, используемые клиентом SSL/libpq
Файл | Содержимое | Действие |
---|---|---|
~/.qhb/qhb.crt | сертификат клиента | передается серверу |
~/.qhb/qhb.key | закрытый ключ клиента | подтверждает сертификат клиента, передаваемый серверу; не говорит от том, что владельцу сертификата можно доверять |
~/.qhb/root.crt | сертификаты доверенных CA | проверяет, что сертификат сервера подписан доверенным CA |
~/.qhb/root.crl | сертификаты, отозванные CA | сертификат сервера не должен присутствовать в этом списке |
Инициализация библиотеки SSL
Если ваше приложение инициализирует библиотеки libssl и/или libcrypto и libpq собрана с поддержкой SSL, вам следует вызвать функцию PQinitOpenSSL, чтобы сообщить libpq, что библиотеки libssl и/или libcrypto были инициализированы вашим приложением, чтобы libpq не пыталась повторно инициализировать их. Однако в этом нет необходимости при использовании OpenSSL версии 1.1.0 или выше, поскольку в ней проблема повторных инициализаций уже решена.
PQinitOpenSSL
Позволяет приложениям выбрать, какие библиотеки безопасности инициализировать.
void PQinitOpenSSL(int do_ssl, int do_crypto);
Когда параметр do_ssl имеет ненулевое значение, libpq будет инициализировать библиотеку OpenSSL перед первым подключением к базе данных. Когда параметр do_crypto имеет ненулевое значение, будет инициализирована библиотека libcrypto. По умолчанию (если функция PQinitOpenSSL не вызывается), инициализируются обе библиотеки. Если поддержка SSL не была скомпилирована, эта функция присутствует, но ничего не делает.
Если ваше приложение использует и инициализирует библиотеку OpenSSL или ее нижележащую библиотеку libcrypto, вы должны вызвать эту функцию, передав нули в соответствующих параметрах, перед первым подключением к базе данных. Саму инициализацию также нужно провести перед первым подключением.
PQinitSSL
Позволяет приложениям выбрать, какие библиотеки безопасности инициализировать.
void PQinitSSL(int do_ssl);
Эта функция равнозначна вызову PQinitOpenSSL(do_ssl, do_ssl). Этого достаточно для приложений, которые инициализируют сразу обе библиотеки OpenSSL и libcrypto или ни одну из них.