Настройка TLS весной
Безопасная связь играет важную роль в современных приложениях. Связь между клиентом и сервером по простому HTTP не является безопасной. Для готового к производству приложения мы должны включить HTTPS через протокол TLS (Transport Layer Security) в нашем приложении. В этом руководстве мы обсудим, как включить технологию TLS в приложении Spring Boot.
2. Протокол TLS
TLS обеспечивает защиту данных при передаче между клиентом и сервером и является ключевым компонентом протокола HTTPS. Secure Sockets Layer (SSL) и TLS часто используются взаимозаменяемо, но это не одно и то же . По сути, TLS является преемником SSL. TLS может быть реализован как односторонним, так и двусторонним.
2.1. Односторонний TLS
В одностороннем TLS только клиент проверяет сервер, чтобы убедиться, что он получает данные с доверенного сервера. Для реализации одностороннего TLS сервер делится своим общедоступным сертификатом с клиентами.
2.2. Двусторонний TLS
В двустороннем TLS или Mutual TLS (mTLS) и клиент, и сервер аутентифицируют друг друга, чтобы гарантировать доверие обеих сторон, участвующих в обмене данными. Для реализации mTLS обе стороны делятся своими публичными сертификатами друг с другом.
3. Настройка TLS в Spring Boot
3.1. Создание пары ключей
Чтобы включить TLS, нам нужно создать пару открытый/закрытый ключ . Для этого мы используем keytool . Команда keytool поставляется с дистрибутивом Java по умолчанию. Давайте используем keytool для создания пары ключей и сохранения ее в файле keystore.p12 :
keytool -genkeypair -alias foreach -keyalg RSA -keysize 4096 \ -validity 3650 -dname "CN=localhost" -keypass changeit -keystore keystore.p12 \ -storeType PKCS12 -storepass changeit
Файл хранилища ключей может быть в разных форматах . Двумя наиболее популярными форматами являются Java KeyStore (JKS) и PKCS#12. JKS специфичен для Java, а PKCS#12 — это стандартный отраслевой формат, принадлежащий к семейству стандартов, определенных в Стандартах криптографии с открытым ключом (PKCS).
3.2. Настройка TLS весной
Начнем с настройки одностороннего TLS. Мы настраиваем свойства, связанные с TLS, в файле application.properties :
# enable/disable https server.ssl.enabled=true # keystore format server.ssl.key-store-type=PKCS12 # keystore location server.ssl.key-store=classpath:keystore/keystore.p12 # keystore password server.ssl.key-store-password=changeit
При настройке протокола SSL мы будем использовать TLS и укажем серверу использовать TLS 1.2:
# SSL protocol to use server.ssl.protocol=TLS # Enabled SSL protocols server.ssl.enabled-protocols=TLSv1.2
Чтобы убедиться, что все работает нормально, нам просто нужно запустить приложение Spring Boot:
3.3. Настройка mTLS в Spring
Для включения mTLS мы используем атрибут client-auth со значением need :
server.ssl.client-auth=need
Когда мы используем значение need , аутентификация клиента необходима и обязательна. Это означает, что и клиент, и сервер должны использовать общий сертификат. Для хранения сертификата клиента в приложении Spring Boot мы используем файл хранилища доверенных сертификатов и настраиваем его в файле application.properties :
#trust store location server.ssl.trust-store=classpath:keystore/truststore.p12 #trust store password server.ssl.trust-store-password=changeit
Путь к хранилищу доверенных сертификатов — это файл, содержащий список центров сертификации, которым машина доверяет для аутентификации сервера SSL. Пароль хранилища доверенных сертификатов — это пароль для доступа к файлу хранилища доверенных сертификатов .
4. Настройка TLS в Tomcat
По умолчанию при запуске Tomcat используется протокол HTTP без каких-либо возможностей TLS. Для включения TLS в Tomcat мы настраиваем файл server.xml :
Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="$/.keystore" keystorePass="changeit" clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1.2"/>
Для включения mTLS мы установим clientAuth=”true” .
5. Вызов HTTPS API
Для вызова REST API мы будем использовать инструмент curl :
curl -v http://localhost:8443/foreach
Так как мы не указали https , будет выведена ошибка:
Bad Request This combination of host and port requires TLS.
Эта проблема решается с помощью протокола https :
curl -v https://localhost:8443/foreach
Однако это дает нам другую ошибку:
SSL certificate problem: self signed certificate
Это происходит, когда мы используем самозаверяющий сертификат. Чтобы это исправить, мы должны использовать сертификат сервера в клиентском запросе. Сначала мы скопируем сертификат сервера foreach.cer из файла хранилища ключей сервера . Затем мы будем использовать сертификат сервера в запросе curl вместе с параметром –cacert :
curl --cacert foreach.cer https://localhost:8443/foreach
6. Заключение
Для обеспечения безопасности данных, передаваемых между клиентом и сервером, TLS может быть реализован как в одностороннем, так и в двустороннем порядке. В этой статье мы опишем, как настроить TLS в приложении Spring Boot в файле application.properties и в файле конфигурации Tomcat. Как обычно, все примеры кода, используемые в этом руководстве, доступны на GitHub.
- 1. Обзор
- 2. Протокол TLS
- 2.1. Односторонний TLS
- 2.2. Двусторонний TLS
- 3.1. Создание пары ключей
- 3.2. Настройка TLS весной
- 3.3. Настройка mTLS в Spring
Простая настройка взаимной проверки подлинности клиента и сервера с использованием TLS
Это руководство посвящено настройке защиты приложений с помощью TLS-аутентификации. При таком подходе возможность работы пользователей с приложением зависит от имеющихся у них сертификатов. То есть — разработчик может самостоятельно принимать решения о том, каким пользователям разрешено обращаться к приложению.

В учебном проекте, который будет здесь разобран, показаны основные настройки сервера и клиента. Их взаимодействие изначально осуществляется посредством HTTP. А это значит, что данные между ними передаются в незашифрованном виде. Наша задача заключается в том, чтобы обеспечить шифрование всего того, чем обмениваются клиент и сервер.
Мы рассмотрим следующие вопросы:
- Запуск сервера
- Отправка приветствия серверу (без шифрования)
- Включение HTTPS на сервере (односторонний TLS)
- Аутентификация клиента (двусторонний TLS)
- Установление двустороннего TLS-соединения с использованием доверенного удостоверяющего центра.
- Автоматизация различных подходов к аутентификации
- Идентификационные данные объекта: хранилище KeyStore, хранящее пару ключей — закрытый (private) и открытый (public).
- TrustStore: хранилище KeyStore, содержащее один или большее количество сертификатов (открытых ключей). Это хранилище содержит список доверенных сертификатов. Оно хранит данные о приложениях, которым доверяет наше приложение.
- Односторонняя аутентификация (односторонний TLS, односторонний SSL): HTTPS-соединение, при установке которого клиент проверяет сертификат противоположной стороны.
- Двусторонняя аутентификация (двусторонний TLS, двусторонний SSL, взаимная аутентификация): HTTPS-соединение, при установке которого клиент и противоположная сторона проверяют сертификаты друг друга.
- Работа с keytool
- Работа с openssl
- Настройка HTTP-клиентов
- Обзор свойств Spring-приложения
1. Запуск сервера
Для того чтобы организовать работу сервера — нам понадобится следующее:
- Java 11
- Maven 3.5.0
- Eclipse, Intellij IDEA (или любой другой текстовой редактор вроде VIM)
- Доступ к терминалу
- Копия этого проекта
В данном проекте содержится Maven-обёртка, поэтому запустить его можно и не устанавливая Maven. Тут будут приведены сведения и о стандартных командах, рассчитанных на mvn, и о командах, ориентированных на использование Maven-обёртки.
Если вы хотите запустить этот проект с использованием Java 8 — вы можете переключиться на более старую его версию с использованием нижеприведённой команды.
git checkout tags/java-8-compatibleПри работе с этой версией проекта рекомендовано следовать инструкциям, подготовленным специально для него. Найти их можно здесь.
Сервер можно привести в рабочее состояние, вызвав метод main класса App или выполнив следующую команду в корневой директории проекта:
cd server/ && mvn spring-boot:runВот команда, рассчитанная на Maven-обёртку:
cd server-with-spring-boot/ && ./../mvnw spring-boot:run2. Отправка приветствия серверу (без шифрования)
Сейчас сервер работает на порте, используемом по умолчанию (8080) без шифрования. С помощью следующей команды, задействующей curl , можно обратиться к конечной точке hello :
curl -i -XGET http://localhost:8080/api/helloОтвет должен выглядеть примерно так:
HTTP/1.1 200 Content-Type: text/plain;charset=UTF-8 Content-Length: 5 Date: Sun, 11 Nov 2018 14:21:50 GMT HelloОбратиться к серверу можно и с использованием клиента, код которого находится в директории client . Клиент зависит от других компонентов проекта. Поэтому, прежде чем его запускать, нужно выполнить в корневой директории проекта команду mvn install или ./mvnw install .
В клиенте реализован интеграционный тест, основанный на Cucumber. Его можно запустить, обратившись к классу ClientRunnerIT из IDE, или выполнив в корневой директории следующую команду:
cd client/ && mvn exec:javaПри использовании Maven-обёртки это будет такая команда:
cd client/ && ./../mvnw exec:javaТут имеется файл Hello.feature, который описывает шаги интеграционного теста. Этот файл можно найти в папке ресурсов теста клиентского проекта.
Есть и другой метод запуска и клиента, и сервера. Он представлен следующей командой, выполняемой в корневой директории проекта:
mvn clean verifyВариант этой команды для Maven-обёртки выглядит так:
./mvnw clean verifyКлиент, по умолчанию, отправляет запросы к localhost , так как он рассчитан на то, что сервер выполняется на том же компьютере, что и он сам. Если сервер работает на другой машине — соответствующий URL можно передать клиенту при запуске, воспользовавшись следующим аргументом VM:
-Durl=http://[HOST]:[PORT]3. Включение HTTPS на сервере (односторонний TLS)
Теперь давайте разберёмся с тем, как защитить сервер с помощью TLS. Сделать это можно, добавив соответствующие свойства в файл application.yml , хранящий настройки приложения.
Речь идёт о следующих настройках:
server: port: 8443 ssl: enabled: trueВозможно, тут у вас появится вопрос о причинах изменения номера порта сервера на 8443 . Дело в том, что tomcat-серверы, поддерживающие HTTPS, принято размещать на порте 8443. А серверы, поддерживающие HTTP — на порте 8080 . Поэтому при настройке подобного соединения можно использовать и порт 8080 , но поступать так не рекомендуется. Тут можно почитать подробности о том, какие номера портов используются в разных ситуациях.
Для того чтобы вышеописанные настройки вступили в силу — сервер надо перезапустить. Возможно, при этом вы увидите следующее исключение:
IllegalArgumentException: Resource location must not be nullПричина его появления заключается в том, что серверу, для установки защищённого соединения с внешними сущностями, нужно хранилище ключей с сертификатом сервера. Сервер может предоставить более подробную информацию об этом в том случае, если воспользоваться следующими аргументами VM:
-Djavax.net.debug=SSL,keymanager,trustmanager,ssl:handshakeДля того решения этой проблемы нужно создать хранилище ключей, содержащее открытый и закрытый ключи для сервера. Открытый ключ будет передаваться пользователям. Так они смогут зашифровать данные, передаваемые серверу. Зашифрованные данные могут быть расшифрованы с использованием закрытого ключа сервера. Закрытый ключ сервера нельзя никому передавать, так как, имея этот ключ, злоумышленник может перехватить зашифрованные данные, которыми обмениваются клиент и сервер, и расшифровать их.
Создать хранилище ключей с открытым и закрытым ключами можно с помощью следующей команды:
keytool -v -genkeypair -dname "CN=Hakan,OU=Amsterdam,O=Thunderberry,C=NL" -keystore shared-server-resources/src/main/resources/identity.jks -storepass secret -keypass secret -keyalg RSA -keysize 2048 -alias server -validity 3650 -deststoretype pkcs12 -ext KeyUsage=digitalSignature,dataEncipherment,keyEncipherment,keyAgreement -ext ExtendedKeyUsage=serverAuth,clientAuth -ext SubjectAlternativeName:c=DNS:localhost,IP:127.0.0.1Теперь нужно сообщить серверу о том, где именно находится хранилище ключей, и указать пароли. Сделаем это, отредактировав наш файл application.yml :
server: port: 8443 ssl: enabled: true key-store: classpath:identity.jks key-password: secret key-store-password: secretЗамечательно! Только что мы настроили TLS-шифрование соединений между сервером и клиентом! Испытать сервер можно так:
curl -i --insecure -v -XGET https://localhost:8443/api/helloКлиент можно запустить и прибегнув к классу ClientRunnerIT.
В результате можно будет увидеть следующее сообщение:
java.net.ConnectException: Connection refused (Connection refused)Возникает такое ощущение, что клиент пытается поприветствовать сервер, а сервер ему найти не удаётся. Проблема заключается в том, что клиент пытается обратиться к серверу, работающему на порте 8080 , а сервер ждёт запросов на порте 8443 . Исправим это, внеся некоторые изменения в класс Constants . А именно — найдём эту строку:
private static final String DEFAULT_SERVER_URL = "http://localhost:8080";И приведём её к такому виду:
private static final String DEFAULT_SERVER_URL = "https://localhost:8443";Попробуем снова запустить клиент. Это приведёт к выдаче такого сообщения:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targetДело тут в том, что клиент собирается наладить обмен данными по HTTPS. Он, при выполнении процедуры рукопожатия, получает сертификат сервера, который он пока не может распознать. А это значит, что нам ещё нужно создать хранилище TrustStore. В таких хранилищах находятся доверенные сертификаты. Клиент сопоставляет то, что он получает в ходе процедуры рукопожатия, с тем, что есть в TrustStore. Если полученный им сертификат входит в список доверенных сертификатов — процедура продолжается. А прежде чем создавать TrustStore — нужно обзавестись сертификатом сервера.
Экспортировать сертификат сервера можно такой командой:
keytool -v -exportcert -file shared-server-resources/src/main/resources/server.cer -alias server -keystore shared-server-resources/src/main/resources/identity.jks -storepass secret -rfcТеперь можно создать TrustStore для клиента и импортировать туда сертификат сервера такой командой:
keytool -v -importcert -file shared-server-resources/src/main/resources/server.cer -alias server -keystore client/src/test/resources/truststore.jks -storepass secret -nopromptTrustStore для клиента мы создали, но сам клиент пока об этом не знает. А это значит, что клиенту надо сообщить о том, что ему следует пользоваться TrustStore, указав адрес хранилища и пароль. Клиенту надо сообщить и о том, что включена аутентификация. Всё это делается путём приведения файла application.yml клиентского приложения к такому виду:
client: ssl: one-way-authentication-enabled: true two-way-authentication-enabled: false trust-store: truststore.jks trust-store-password: secret4. Аутентификация клиента (двусторонний TLS)
Следующий шаг нашей работы заключается такой настройке сервера, чтобы он требовал бы аутентификации клиентов. Благодаря этим настройкам мы принудим клиентов идентифицировать себя. При таком подходе сервер тоже сможет проверить подлинность клиента, и то, входит ли он в число доверенных сущностей. Включить аутентификацию клиентов можно, воспользовавшись свойством client-auth , сообщив серверу о том, что ему нужно проверять клиентов.
Приведём файл сервера application.yml к такому виду:
server: port: 8443 ssl: enabled: true key-store: classpath:identity.jks key-password: secret key-store-password: secret client-auth: needЕсли после этого запустить клиент, то он выдаст следующее сообщение об ошибке:
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificateЭто указывает на то, что клиент не обладает подходящим сертификатом. Точнее — у клиента пока вообще нет сертификата. Поэтому создадим сертификат следующей командой:
keytool -v -genkeypair -dname "CN=Suleyman,OU=Altindag,O=Altindag,C=NL" -keystore client/src/test/resources/identity.jks -storepass secret -keypass secret -keyalg RSA -keysize 2048 -alias client -validity 3650 -deststoretype pkcs12 -ext KeyUsage=digitalSignature,dataEncipherment,keyEncipherment,keyAgreement -ext ExtendedKeyUsage=serverAuth,clientAuthНам ещё нужно создать TrustStore для сервера. Но, прежде чем создавать это хранилище, нужно иметь сертификат клиента. Экспортировать его можно так:
keytool -v -exportcert -file client/src/test/resources/client.cer -alias client -keystore client/src/test/resources/identity.jks -storepass secret -rfcТеперь создадим TrustStore сервера, в котором будет сертификат клиента:
keytool -v -importcert -file client/src/test/resources/client.cer -alias client -keystore shared-server-resources/src/main/resources/truststore.jks -storepass secret -nopromptМы создали для клиента дополнительное хранилище ключей, но клиент об этом не знает. Сообщим ему сведения об этом хранилище. Кроме того, клиенту нужно сообщить о том, что включена двусторонняя аутентификация.
Приведём файл application.yml клиента к такому виду:
client: ssl: one-way-authentication-enabled: false two-way-authentication-enabled: true key-store: identity.jks key-password: secret key-store-password: secret trust-store: truststore.jks trust-store-password: secretСервер тоже не знает о только что созданном для него TrustStore. Приведём его файл application.yml к такому виду:
server: port: 8443 ssl: enabled: true key-store: classpath:identity.jks key-password: secret key-store-password: secret trust-store: classpath:truststore.jks trust-store-password: secret client-auth: needЕсли снова запустить клиент — можно будет убедиться в том, что тест завершается успешно, и что клиент получает данные от сервера в защищённом виде.
Примите поздравления! Только что вы настроили двусторонний TLS!
5. Установление двустороннего TLS-соединения с использованием доверенного удостоверяющего центра
Есть и другой способ организации двусторонней аутентификации. Он основан на использовании доверенного удостоверяющего центра. У такого подхода есть сильные и слабые стороны.
- Клиентам не нужно добавлять в свои хранилища сертификат сервера.
- Серверу не нужно добавлять в своё хранилище все сертификаты клиентов.
- Меньше времени уходит на поддержку такой конфигурации, так как срок действия может истечь лишь у сертификата удостоверяющего центра.
- Разработчик теряет контроль над тем, каким приложениям разрешено обращаться к его приложению. Разрешение даётся любому приложению, у которого есть подписанный сертификат от удостоверяющего центра.
1. Создание удостоверяющего центра
Обычно работают с уже существующими удостоверяющими центрами, которым, для подписи, нужно передавать сертификаты. Здесь же мы создадим собственный удостоверяющий центр и подпишем с его помощью сертификаты клиента и сервера. Для создания удостоверяющего центра воспользуемся такой командой:
keytool -v -genkeypair -dname "CN=Root-CA,OU=Certificate Authority,O=Thunderberry,C=NL" -keystore root-ca/identity.jks -storepass secret -keypass secret -keyalg RSA -keysize 2048 -alias root-ca -validity 3650 -deststoretype pkcs12 -ext KeyUsage=digitalSignature,keyCertSign -ext BasicConstraints=ca:true,PathLen:3Ещё можно воспользоваться существующим удостоверяющим центром.
2. Создание файла запроса на подпись сертификата
Для того чтобы подписать сертификат — нужен .csr-файл (Certificate Signing Request, файл запроса на подпись сертификата). Создать его можно с помощью особой команды.
Вот её вариант для сервера:
keytool -v -certreq -file shared-server-resources/src/main/resources/server.csr -keystore shared-server-resources/src/main/resources/identity.jks -alias server -keypass secret -storepass secret -keyalg rsaВот — эта команда для клиента:
keytool -v -certreq -file client/src/test/resources/client.csr -keystore client/src/test/resources/identity.jks -alias client -keypass secret -storepass secret -keyalg rsaТакой файл нужен удостоверяющему центру для подписи сертификата. Следующий шаг нашей работы заключается в подписании сертификата.
3. Подписание сертификата с помощью запроса на подпись сертификата
Вот соответствующая команда для клиента:
keytool -v -gencert -infile client/src/test/resources/client.csr -outfile client/src/test/resources/client-signed.cer -keystore root-ca/identity.jks -storepass secret -alias root-ca -ext KeyUsage=digitalSignature,dataEncipherment,keyEncipherment,keyAgreement -ext ExtendedKeyUsage=serverAuth,clientAuthВот команда для сервера:
keytool -v -gencert -infile shared-server-resources/src/main/resources/server.csr -outfile shared-server-resources/src/main/resources/server-signed.cer -keystore root-ca/identity.jks -storepass secret -alias root-ca -ext KeyUsage=digitalSignature,dataEncipherment,keyEncipherment,keyAgreement -ext ExtendedKeyUsage=serverAuth,clientAuth -ext SubjectAlternativeName:c=DNS:localhost,IP:127.0.0.14. Замена неподписанного сертификата подписанным
В хранилище идентификационных данных сервера и клиента всё ещё хранится неподписанный сертификат. Сейчас можно заменить его на подписанный. У инструмента keytool есть одна не вполне понятная особенность. А именно — он не позволяет напрямую импортировать в хранилище подписанный сертификат. Если попытаться это сделать — будет выведено сообщение об ошибке. Сертификат, подписанный удостоверяющим центром, должен быть представлен в файле identity.jks .
Экспортируем подписанный сертификат:
keytool -v -exportcert -file root-ca/root-ca.pem -alias root-ca -keystore root-ca/identity.jks -storepass secret -rfcВыполним на клиенте следующие команды:
keytool -v -importcert -file root-ca/root-ca.pem -alias root-ca -keystore client/src/test/resources/identity.jks -storepass secret -noprompt keytool -v -importcert -file client/src/test/resources/client-signed.cer -alias client -keystore client/src/test/resources/identity.jks -storepass secret keytool -v -delete -alias root-ca -keystore client/src/test/resources/identity.jks -storepass secretНа сервере выполним такие команды:
keytool -v -importcert -file root-ca/root-ca.pem -alias root-ca -keystore shared-server-resources/src/main/resources/identity.jks -storepass secret -noprompt keytool -v -importcert -file shared-server-resources/src/main/resources/server-signed.cer -alias server -keystore shared-server-resources/src/main/resources/identity.jks -storepass secret keytool -v -delete -alias root-ca -keystore shared-server-resources/src/main/resources/identity.jks -storepass secret5. Организация взаимодействия клиента и сервера, основанного исключительно на доверии к удостоверяющему центру
Теперь нужно настроить клиент и сервер так, чтобы они доверяли бы только удостоверяющему центру. Сделать это можно, импортировав сертификат удостоверяющего центра в хранилища TrustStore клиента и сервера.
Сделаем это, выполнив на клиенте следующую команду:
keytool -v -importcert -file root-ca/root-ca.pem -alias root-ca -keystore client/src/test/resources/truststore.jks -storepass secret -nopromptНа сервере выполним такую команду:
keytool -v -importcert -file root-ca/root-ca.pem -alias root-ca -keystore shared-server-resources/src/main/resources/truststore.jks -storepass secret -nopromptВ хранилищах TrustStore всё ещё хранятся собственные сертификаты клиента и сервера. Эти сертификаты нужно удалить.
Выполним на клиенте такую команду:
keytool -v -delete -alias server -keystore client/src/test/resources/truststore.jks -storepass secretВот — команда для сервера:
keytool -v -delete -alias client -keystore shared-server-resources/src/main/resources/truststore.jks -storepass secretЕсли снова запустить клиент — можно видеть успешное прохождение теста. А это значит, что клиент и сервер успешно обмениваются данными, используя сертификаты, подписанные удостоверяющим центром.
6. Автоматизация различных подходов к аутентификации
Всё, о чём мы говорили выше, можно автоматизировать с помощью скриптов, которые находятся в папке script рассматриваемого нами проекта. Для запуска скриптов можете воспользоваться следующими командами:
- ./configure-one-way-authentication — настройка односторонней аутентификации.
- ./configure-two-way-authentication-by-trusting-each-other my-company-name — настройка двусторонней аутентификации.
- ./configure-two-way-authentication-by-trusting-root-ca my-company-name — настройка двусторонней аутентификации с использованием удостоверяющего центра.
Протестированные клиенты
Ниже приведён список протестированных клиентов. Настройки для HTTP-клиента, написанного на чистом Java, можно найти в классе ClientConfig. В директории service нашего проекта содержатся отдельные HTTP-клиенты, выполняющие демонстрационные запросы. Настройки HTTP-клиентов, основанных на Kotlin и Scala, включены в состав проекта в виде вложенных классов. Все примеры клиентов используют одну и ту же базовую конфигурацию SSL, созданную в классе SSLConfig.
- Apache HttpClient → Настройки клиента | Пример запроса
- Apache HttpAsyncClient → Настройки клиента | Пример запроса
- Apache 5 HttpClient → Настройки клиента | Пример запроса
- Apache 5 HttpAsyncClient → Настройки клиента | Пример запроса
- JDK HttpClient → Настройки клиента | Пример запроса
- Old JDK HttpClient → Настройки клиента и пример запроса
- Netty Reactor → Настройки клиента | Пример запроса
- Jetty Reactive HttpClient → Настройки клиента | Пример запроса
- Spring RestTemplate → Настройки клиента | Пример запроса
- Spring WebFlux WebClient Netty → Настройки клиента | Пример запроса
- Spring WebFlux WebClient Jetty → Настройки клиента | Пример запроса
- OkHttp → Настройки клиента | Пример запроса
- Клиент Jersey → Настройки клиента | Пример запроса
- Старый клиент Jersey → Настройки клиента | Пример запроса
- Google HttpClient → Настройки клиента | Пример запроса
- Unirest → Настройки клиента | Пример запроса
- Retrofit → Настройки клиента | Пример запроса
- Асинхронный Http-клиент → Настройки клиента | Пример запроса
- Feign → Настройки клиента | Пример запроса
- Methanol → Настройки клиента | Пример запроса
- Vertx Webclient → Настройки клиента и пример запроса
- Fuel → Настройки клиента и пример запроса
- Http4k с Apache 4 → Настройки клиента | Пример запроса
- Http4k с Async Apache 4 → Настройки клиента | Пример запроса
- Http4k с Apache 5 → Настройки клиента | Пример запроса
- Http4k с Async Apache 5 → Настройки клиента | Пример запроса
- Http4k с Java Net → Настройки клиента | Пример запроса
- Http4k с Jetty → Настройки клиента | Пример запроса
- Http4k с OkHttp → Настройки клиента | Пример запроса
- Kohttp → Настройки клиента и пример запроса
- Ktor с движком Android → Настройки клиента | Пример запроса
- Ktor с движком Apache → Настройки клиента | Пример запроса
- Ktor c CIO-движком (I/O на основе корутин) → Настройки клиента | Пример запроса
- Ktor с движком Okhttp → Настройки клиента | Пример запроса
- Twitter Finagle → Настройки клиента | Пример запроса
- Twitter Finagle Featherbed → Настройки клиента и пример запроса
- HTTP-клиент Akka → Настройки клиента | Пример запроса
- Dispatch Reboot → Настройки клиента и пример запроса
- ScalaJ / Simplified Http Client → Настройки клиента и пример запроса
- Sttp → Настройки клиента и пример запроса
- Requests-Scala → Настройки клиента и пример запроса
- Клиент Http4s Blaze → Настройки клиента | Пример запроса
- Клиент Http4s Java Net → Настройки клиента | Пример запроса

Предварительные условия
- Изучение этого раздела предполагает предварительное ознакомление с разделом Создание запросов для сторонних служб сертификатов.
Шаг 1. Создание запроса на сертификаты TLS
Компания Contoso имеет внутреннюю инфраструктуру PKI, которая подчиняется стороннему центру сертификации. В этом сценарии подчиненность значит, что центр сертификации, развернутый компанией Contoso в своей корпоративной инфраструктуре, содержит корневой сертификат, подписанный общим сторонним центром сертификации. По умолчанию общедоступный сторонний центр сертификации является одним из доверенных корневых сертификатов в хранилище сертификатов Microsoft Windows. Поэтому любой клиент, который включает такой сторонний центр сертификации в свое доверенное корневое хранилище и подключается к компании Contoso, может проверить подлинность сертификата, представленного компанией Contoso.
В компании Contoso имеется два пограничных транспортных сервера, для которых необходимы сертификаты TLS: mail1.contoso.com и mail2.mail.contoso.com. Поэтому администратор электронной почты компании Contoso должен создать два запроса на сертификаты — по одному запросу на сертификат для каждого сервера.
В следующем примере показаны команды, которые использует администратор для создания запросов на сертификат PKCS#10 с кодировкой base64.
Администратору Contoso необходимо запустить эту команду для CN=mail1.contoso.com.
$Data1 = New-ExchangeCertificate -GenerateRequest -FriendlyName "Internet certificate for mail1" -SubjectName "DC=com,DC=Contoso,CN=mail1.contoso.com" -DomainName mail.contoso.com Set-Content -Path "C:\Certificates\mail1-request.req" -Value $Data1
Администратору Contoso необходимо запустить эту команду для CN=mail2.mail.contoso.com.
$Data2 = New-ExchangeCertificate -GenerateRequest -FriendlyName "Internet certificate for mail2" -SubjectName "DC=com,DC=Contoso,CN=mail2.mail.contoso.com" -DomainName mail.contoso.com Set-Content -Path "C:\Certificates\mail2-request.req" -Value $Data2
Дополнительные сведения о синтаксисе и параметрах команды см. в разделе New-ExchangeCertificate.
Важно! Конкретные параметры создаваемого сертификата или запроса сертификата зависят от многих переменных. При создании запроса убедитесь, что сотрудничайте непосредственно с администратором центра сертификации или PKI, который будет выдавать сертификат. Дополнительные сведения о создании запроса на сертификат TLS см. в разделе Создание запросов для сторонних служб сертификатов. Шаг 2. Импорт сертификатов на пограничные транспортные серверы
После создания запросов на сертификаты администратором Contoso администратор центра сертификации для компании Contoso использует эти запросы, чтобы создать сертификаты для серверов. Итоговые сертификаты должны выпускаться или в виде одиночного сертификата, или в виде цепочки сертификатов и копироваться на соответствующие пограничные транспортные серверы.
Важно! Не используйте оснастку диспетчера сертификатов в консоли управления Microsoft (MMC) для импорта сертификатов TLS на сервер Exchange. При использовании оснастки диспетчера сертификатов для импорта сертификатов на серверы Exchange не выполняется привязка созданного с помощью этой процедуры запроса к выданному сертификату. Поэтому протокол TLS может не работать. Оснастку диспетчера сертификатов можно использовать для импорта сертификатов и ключей, которые хранятся в PFX-файлах, в хранилище локального компьютера. При импорте сертификата на пограничный транспортный сервер необходимо также включить сертификат для службы SMTP. Администратор компании Contoso выполняет следующую команду на каждом пограничном транспортном сервере по одному разу для каждого соответствующего сертификата.
Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path C:\Certificates\mail1-certificate.pfx -Encoding Byte -ReadCount 0)) | Enable-ExchangeCertificate -Services SMTP
В предыдущем примере показано, как импортировать и включить сертификат TLS с помощью передачи сертификата по конвейеру в командлет Enable-ExchangeCertificate. Можно также задействовать сертификат после того, как он импортирован. В этом случае необходимо указать отпечаток сертификата, который необходимо включить.
Дополнительные сведения о синтаксисе и параметрах см. в разделах Import-ExchangeCertificate и Enable-ExchangeCertificate.
Перенос сертификатов и связанных с ними ключей
После получения сертификата от поставщика PKI или центра сертификации преобразуйте его в PFX-файл (PKCS#12), чтобы создать его резервную копию на случай сбоя. PFX-файл содержит сертификат и связанные с ним ключи. В некоторых ситуациях может потребоваться перенести сертификат и ключи на другие компьютеры. Например, при наличии нескольких пограничных транспортных серверов, на которых необходимо получать и отправлять электронную почту, защищенную на уровне домена, можно создать один сертификат для всех серверов. В этом случае необходимо импортировать сертификат на каждый пограничный транспортный сервер, а затем включить для него поддержку TLS.
Если копия PFX-файла надежно заархивирована, импортировать и включить сертификат можно в любое время. PFX-файл содержит закрытый ключ, поэтому важно физически защитить его. Храните носитель с закрытым ключом в безопасном месте.
Важно понимать, что командлет Import-ExchangeCertificate всегда помечает импортированный из PFX-файла закрытый ключ как неэкспортируемый. Это не является ошибкой.
При использовании оснастки диспетчера сертификатов в консоли управления Microsoft (MMC) для импорта PFX-файла можно указать возможность экспорта закрытого ключа и сильную защиту ключа.
Важно! Не включайте сильную защиту ключа для сертификатов, предназначенных для TLS. При сильной защите ключа при каждом доступе к закрытому ключу выводится запрос для пользователя. При использовании безопасности домена «пользователем» является служба SMTP на пограничном транспортном сервере. Шаг 3. Настройка безопасности домена для исходящих сообщений
Чтобы настроить безопасность домена для исходящих сообщений, необходимо выполнить следующие три шага:
-
Выполнить командлет Set-TransportConfig, чтобы задать домен, с которого предполагается отправлять сообщения электронной почты безопасного домена.
-
Соединитель отправления, который будет отправлять почту в домен, с которого предполагается отправлять сообщения электронной почты безопасного домена, маршрутизирует почту с помощью службы доменных имен (DNS).
Т.к. изменения, осуществляемые за эти три шага, являются глобальными, следует выполнить изменения на внутреннем сервере Exchange. Выполненные изменения конфигурации будут реплицированы на пограничные транспортные серверы с помощью службы Microsoft Exchange EdgeSync.
Шаг 3а. Указание домена отправителя в конфигурации транспорта
Это относительно простой способ указания домена, с которого необходимо отправлять электронную почту, защищенную на уровне домена. Администратор компании Contoso выполняет следующую команду на внутреннем сервере Exchange 2010:
Set-TransportConfig -TLSSendDomainSecureList woodgrovebank.com
В параметре TLSSendDomainSecureList используется многозначный список доменных имен. Команда Set-TransportConfig полностью заменяет значение параметра TLSSendDomainSecureList новым значением, указанным в командлете. Поэтому, если другие домены уже настроены и предполагается добавить новый домен, необходимо добавить существующий домен в список или использовать временную переменную. В следующем примере показано, как добавить домен woodgrovebank.com в параметр TLSSendDomainSecureList без перезаписи существующих значений.
$TransportConfig = Get-TransportConfig $TransportConfig.TLSSendDomainSecureList += "woodgrovebank.com" Set-TransportConfig -TLSSendDomainSecureList $TransportConfig.TLSSendDomainSecureList
Дополнительные сведения о синтаксисе и параметрах см. в разделе Set-TransportConfig.
Шаг 3б. Настройка соединителя отправки по умолчанию
Компания Contoso будет использовать соединитель отправки по умолчанию с поддержкой DNS-маршрутизации с именем «Интернет» для отправки партнерам электронной почты, защищенной на уровне домена. Так как соединитель отправки по умолчанию с поддержкой DNS-маршрутизации является соединителем отправки для Интернета по умолчанию, в нем для маршрутизации почты используется служба DNS и не используется промежуточный узел. Для полного доменного имени уже установлено значение mail.contoso.com . Так как сертификаты, созданные администратором Contoso, устанавливают для параметра DomainName командлета New-ExchangeCertificate значение mail.contoso.com , соединитель отправки может использовать эти сертификаты без дополнительной настройки.
Если поддомен настроен для тестирования, может потребоваться обновить имя FQDN соединителя отправки в соответствии созданному сертификату (например, subdomain.mail.contoso.com). С другой стороны, если создан сертификат, в полях имени субъекта или дополнительного имени субъекта которого указан поддомен, обновлять имя FQDN соединителя отправки не требуется.
Поэтому единственной настройкой, которую должен выполнить администратор компании Contoso в отношении соединителя отправки, является указание значения параметра DomainSecureEnabled. Для этого администратор Contoso выполняет следующую команду на внутреннем сервере Exchange 2010 для соединителя отправки «Интернет»:
Set-SendConnector Internet -DomainSecureEnabled:$true
Дополнительные сведения о синтаксисе и параметрах см. в разделе Set-SendConnector.
Шаг 3в. Проверка конфигурации соединителя отправки
После выполнения изменений конфигурации администратору Contoso необходимо убедиться, что соединитель отправки, используемый для безопасности домена, настроен правильно. Для этого администратор Contoso должен выполнить следующую команду.
Get-SendConnector Internet | Format-List Name,DNSRoutingEnabled,FQDN,DomainSecureEnabled
Эта команда отображает список соответствующих параметров, настроенных для безопасности домена, и позволяет администратору Contoso проверить конфигурацию.
Дополнительные сведения о синтаксисе и параметрах см. в разделе Get-SendConnector.
Шаг 4. Настройка безопасности домена для входящих сообщений
Чтобы настроить безопасность домена для входящих сообщений, необходимо выполнить следующие два шага:
-
Выполнить командлет Set-TransportConfig, чтобы задать домен, из которого предполагается получать сообщения электронной почты безопасного домена.
Шаг 4а. Указание домена получателя в конфигурации транспорта
Это относительно простой способ указания домена, с которого необходимо получать электронную почту, защищенную на уровне домена. Чтобы указать домен, администратору компании Contoso необходимо выполнить следующую команду в командной консоли Exchange на внутреннем сервере Exchange 2010 или управляющей рабочей станции.
Set-TransportConfig -TLSReceiveDomainSecureList woodgrovebank.com
В параметре TLSReceiveDomainSecureList используется многозначный список доменных имен. Команда Set-TransportConfig полностью заменяет значение параметра TLSReceiveDomainSecureList новым значением, указанным в командлете Set-TransportConfig. Поэтому, если другие домены уже настроены и предполагается добавить новый домен, необходимо добавить существующий домен в список или использовать временную переменную. В следующем примере показано, как добавить домен woodgrovebank.com в параметр TLSReceiveDomainSecureList без перезаписи существующих значений.
$TransportConfig = Get-TransportConfig $TransportConfig.TLSReceiveDomainSecureList += "woodgrovebank.com" Set-TransportConfig -TLSReceiveDomainSecureList $TransportConfig.TLSReceiveDomainSecureList
Дополнительные сведения о синтаксисе и параметрах см. в разделе Set-TransportConfig.
Шаг 4б. Настройка соединителя получения
Следует настроить соединитель приема на каждом пограничном транспортном сервере, принимающем почту из домена, из которого предполагается принимать сообщения электронной почты безопасного домена. Среда компании Contoso настраивается так, чтобы на обоих пограничных транспортных серверах использовался один соединитель получения «Интернет» со значением параметра Identity «Интернет». Следовательно, для включения протокола TLS при отправке почты в банк Woodgrove Bank или получения почты из этого банка, администратору компании Contoso следует убедиться, что протокол TLS включен на соединителе приема для Интернета по умолчанию или обоих пограничных транспортных серверах. Для этого администратор Contoso на серверах mail1.contoso.com и mail2.mail.contoso.com выполняет следующую команду.
Set-ReceiveConnector Internet -DomainSecureEnabled $true -AuthMechanism TLS
Дополнительные сведения о синтаксисе и параметрах команды см. в разделе Set-ReceiveConnector.
Кроме того, чтобы настроить соединитель получения, в консоли управления Exchange можно выполнить следующие шаги.
-
На пограничном транспортном сервере откройте консоль управления Exchange, выберите Пограничный транспортный сервер и в области результатов откройте вкладку Соединители получения.
Имейте ввиду, что задание механизма проверки подлинности в виде протокола TLS не приводит к использованию протокола TLS на всех входящих подключениях.
Протокол TLS принудительно включается для подключений от банка Woodgrove Bank по следующим причинам:
-
Банк Woodgrove Bank указан в командлете Set-TransportConfig с помощью параметра TLSReceiveDomainSecureList.
Другие отправители, которые не указаны в списке параметра TLSReceiveDomainSecureList командлета Set-TransportConfig, будут использовать протокол TLS, только если он поддерживается системой-отправителем.
Шаг 5. Проверка потока почты безопасного домена
После настройки электронной почты, защищенной на уровне домена, можно проверить подключение. Для этого необходимо просмотреть журналы производительности и журналы протоколов. Сообщения, успешно прошедшие проверку подлинности на всем пути потока почты, защищенной на уровне домена, отображаются в Outlook в виде сообщений «Защищено на уровне домена».
Счетчики производительности
Функция безопасности домена включает в себя следующий набор счетчиков производительности под заголовком Безопасный почтовый транспорт MSExchange:
-
Получено сообщений, защищенных на уровне домена
Можно создать новый файл журнала счетчиков для потока почты безопасного домена с этими счетчиками производительности, чтобы отслеживать число отправленных и полученных сообщений, а также отслеживать неудачные сеансы с использованием функции Mutual TLS. Дополнительные сведения о создании и настройке журналов счетчиков см. в файле справки в оснастке консоли управления Microsoft (MMC) Журналы и оповещения производительности.
Журналы протоколов
Можно просмотреть журналы протоколов отправки и получения, чтобы определить, успешно ли выполнено TLS-согласование.
Чтобы просмотреть дополнительные сведения журналов протокола, необходимо установить уровень ведения журнала протокола Verbose для соединителей, используемых для отправки и получения в организации электронной почты, защищенной на уровне домена. Для этого администратор компании Contoso выполняет следующую команду на обоих пограничных транспортных серверах.
Set-ReceiveConnector Internet -ProtocolLoggingLevel Verbose
Чтобы включить ведение журнала протокола на соединителе отправки, администратор Contoso на внутреннем сервере Exchange или управляющей рабочей станции выполняет следующие действия. Затем изменение конфигурации реплицируется на пограничные транспортные серверы с помощью службы Microsoft Exchange EdgeSync.
Set-SendConnector Internet -ProtocolLoggingLevel Verbose
Дополнительные сведения о синтаксисе и параметрах см. в разделах Set-ReceiveConnector и Set-SendConnector.
Дополнительные сведения о том, как просматривать журналы протоколов, см. в разделе Настройка ведения журнала протокола.
© Корпорация Майкрософт (Microsoft Corporation), 2010. Все права защищены. Юридические сведения
Настройка mTLS в NGINX на Linux

Опубликовано: 28.10.2023
- Создание сертификатов сервера и клиента.
- Настройку NGINX для аутентификации клиента.
- Создание и настройку инфраструктуры отзыва сертификатов.
Изучим работу с mTLS в NGINX по шагам.
Настройка mTLS на NGINX
В рамках данной инструкции мы не будем рассматривать установку и базовую настройку NGINX, а сосредоточим внимание на mTLS. Процесс разобьем на этапы.
Настройка HTTPS
Наш веб-сервер должен принимать запросы по https. Для этого необходимо получить сертификат. Для тестовых целей мы будем использовать самоподписанный — создадим каталог для его хранения:
openssl req -new -x509 -days 1461 -nodes -out /etc/ssl/server/cert.crt -keyout /etc/ssl/server/cert.key -subj «/CN=mtls.dmosk.local»
* это простой способ создать сертификат с открытым и закрытым ключами в каталоге /etc/ssl/server.
Редактируем файл виртуального домена NGINX. Данных файлов может быть несколько, как правило, они расположены в каталогах:
- /etc/nginx/sites-enabled (sites-available).
- /etc/nginx/conf.d.
Или можно открыть конфигурационный файл с доменом по умолчанию. Он также может иметь различное расположение, например:
Для настройки https должны быть настроены директивы:
- listen — указать порт, на котором слушать запросы (для https, как правило, 443), а также опцию ssl.
- ssl_certificate — путь до файла с открытым ключом.
- ssl_certificate_key — путь до файла с закрытым ключом.
В моем случае конфигурация имела такие значения вышеописанных опций:
server .
listen 443 ssl;
.
ssl_certificate /etc/ssl/server/cert.pem;
ssl_certificate_key /etc/ssl/server/cert.key;
.
>Для проверки можно выполнить curl-запрос:
curl -k https://127.0.0.1
Сервер должен вернуть html для страницы вашего сайта. HTTPS настроен — переходим к настройке mTLS.
Настройка аутентификации клиента
Завершаем настройку mTLS, указав, что веб-сервер NGINX должен проверять клиента. Нам нужно сформировать клиентский сертификат. Мы также будем использовать самозаверенные ключи.
Создадим каталог, где будут находиться сертификаты и перейдем в него:
Сформируем ключи для центра сертификации:
openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -days 3650 -subj «/C=RU/ST=SPb/L=SPb/O=Global Security/OU=IT Department/CN=ca» -out ca.crt
Этого достаточно для настройки NGINX — открываем конфигурационный файл (в нашем примере мы работали с доменом по умолчанию):
Добавил такие директивы:
server .
ssl_client_certificate /etc/ssl/client/ca.crt;
ssl_verify_client on;
.
>- ssl_client_certificate — путь до открытого ключа центра сертификации, который будет использоваться для проверки клиентов.
- ssl_verify_client — включает или отключает проверку сертификатов. В нашем случае, включает.
Проверяем корректность конфигурации веб-сервера и перезапускаем его:
nginx -t && nginx -s reload
Теперь пробуем сделать http-запрос:
curl -k https://127.0.0.1
Мы должны получить ошибку:
400 No required SSL certificate was sent
400 Bad Request
No required SSL certificate was sent
nginx/1.25.2
Теперь, чтобы наши запросы к серверу проходили, нужно использовать сертификат, выданный центром сертификации, ключ которого прописан в nginx.
Подключение клиента к веб-серверу
Теперь рассмотрим, как создать клиентский сертификат и использовать его.
Создание клиентского сертификата
Предполагается, что мы по-прежнему, находимся в каталоге с клиентскими сертификатами:
Для удобства, создаем переменную, значением которой будет порядковый номер сертификата:
Создадим файл запроса сертификата:
openssl req -newkey rsa:2048 -keyout client$.key -out client$.csr -nodes -days 731 -subj «/CN=client$»
* в результате мы получим файл закрытого ключа client01.key и файл запроса client01.csr.
Теперь выдадим клиентский сертификат, заверив его ключом центра сертификации:
openssl x509 -req -in client$.csr -out client$.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 731
* будет сформирован ключ client01.crt. Мы используем ключи центра сертификации ca.crt и ca.key, которые сформировали ранее, а открытый ключ указали в nginx для аутентификации клиентов.
Теперь попробуем воспользоваться данными сертификатами, чтобы сделать http-запрос:
curl -k —key client$.key —cert client$.crt https://127.0.0.1
На этот раз, мы должны увидеть html-код, сформированный сервером.
Настройка клиента Windows
В качестве примера, рассмотрим настройку системы Windows.
Если мы попробуем перейти на веб-страницу с настроенным mTLS, браузер должен вернуть ошибку 400:

Идем на наш сервер в каталог, где лежат созданные клиентские сертификаты.
openssl pkcs12 -inkey client$.key -in client$.crt -export -out client$.pfx
Обязательно, вводим пароль.
Полученный файл (в нашем случае, client01.pfx) копируем на компьютер с Windows и выполняем импорт в браузер.
Возможно, браузер придется перезагрузить. После чего при переходе на сайт, должно появится окно с запросом сертификата — выбираем тот, что импортировали. Сайт должен открыться.
Отзыв сертификата
Рассмотрим как процесс настройки сервера, так и отзыва сертификата.
Подготовка сервера
Наш сервер должен быть настроен для возможности отозвать сертификат.
Мы должны быть в каталоге с клиентскими сертификатами:
Создадим каталог demoCA и в нем 2 файла: