view xml/ru/docs/http/configuring_https_servers.xml @ 2769:16f6fa718be2

Updated TLSv1.3 support notes. Previous notes described some early development snapshot of OpenSSL 1.1.1 with disabled TLSv1.3 by default. It was then enabled in the first alpha. Further, the updated text covers later major releases such as OpenSSL 3.0.
author Sergey Kandaurov <pluknet@nginx.com>
date Thu, 30 Sep 2021 16:29:20 +0300
parents aac9e462320b
children 37e082fd009c
line wrap: on
line source

<!--
  Copyright (C) Igor Sysoev
  Copyright (C) Nginx, Inc.
  -->

<!DOCTYPE article SYSTEM "../../../../dtd/article.dtd">

<article name="Настройка HTTPS-серверов"
         link="/ru/docs/http/configuring_https_servers.html"
         lang="ru"
         rev="13"
         author="Игорь Сысоев"
         editor="Brian Mercer">

<section>

<para>
Чтобы настроить HTTPS-сервер, необходимо включить параметр
<literal>ssl</literal> на
<link doc="ngx_http_core_module.xml" id="listen">слушающих сокетах</link>
в блоке <link doc="ngx_http_core_module.xml" id="server"/>,
а также указать местоположение файлов с
<link doc="ngx_http_ssl_module.xml" id="ssl_certificate">сертификатом сервера</link>
и
<link doc="ngx_http_ssl_module.xml" id="ssl_certificate_key">секретным ключом</link>:

<programlisting>
server {
    listen              443 <b>ssl</b>;
    server_name         www.example.com;
    ssl_certificate     <b>www.example.com.crt</b>;
    ssl_certificate_key <b>www.example.com.key</b>;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}
</programlisting>

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

<programlisting>
    ssl_certificate     www.example.com.cert;
    ssl_certificate_key www.example.com.cert;
</programlisting>

при этом права доступа к файлу следует также ограничить.
Несмотря на то, что и сертификат, и ключ хранятся в одном файле,
клиенту посылается только сертификат.
</para>

<para>
С помощью директив <link doc="ngx_http_ssl_module.xml" id="ssl_protocols"/> и
<link doc="ngx_http_ssl_module.xml" id="ssl_ciphers"/>
можно ограничить соединения
использованием только “сильных” версий и шифров SSL/TLS.
По умолчанию nginx использует
“<literal>ssl_protocols TLSv1 TLSv1.1 TLSv1.2</literal>” и
“<literal>ssl_ciphers HIGH:!aNULL:!MD5</literal>”,
поэтому их явная настройка в общем случае не требуется.
Следует отметить, что значения по умолчанию этих директив несколько раз
<link id="compatibility">менялись</link>.
</para>

</section>


<section id="optimization" name="Оптимизация HTTPS-сервера">

<para>
SSL-операции потребляют дополнительные ресурсы процессора.
На мультипроцессорных системах следует запускать несколько
<link doc="../ngx_core_module.xml" id="worker_processes">рабочих процессов</link>,
не меньше числа доступных процессорных ядер.
Наиболее ресурсоёмкой для процессора является операция SSL handshake, в рамках
которой формируются криптографические параметры сессии.
Существует два способа уменьшения числа этих операций, производимых для каждого
клиента: использование постоянных
(<link doc="ngx_http_core_module.xml" id="keepalive_timeout">keepalive</link>)
соединений, позволяющих в рамках
одного соединения обрабатывать сразу несколько запросов, и повторное
использование параметров SSL-сессии для предотвращения необходимости выполнения
SSL handshake для параллельных и последующих соединений.
Сессии хранятся в кэше SSL-сессий, разделяемом между рабочими процессами и
настраиваемом директивой
<link doc="ngx_http_ssl_module.xml" id="ssl_session_cache"/>.
В 1 мегабайт кэша помещается около 4000 сессий.
Таймаут кэша по умолчанию равен 5 минутам.
Он может быть увеличен с помощью директивы
<link doc="ngx_http_ssl_module.xml" id="ssl_session_timeout"/>.
Вот пример конфигурации, оптимизированной под многоядерную систему
с 10-мегабайтным разделяемым кэшем сессий:

<programlisting>
<b>worker_processes auto</b>;

http {
    <b>ssl_session_cache   shared:SSL:10m</b>;
    <b>ssl_session_timeout 10m</b>;

    server {
        listen              443 ssl;
        server_name         www.example.com;
        <b>keepalive_timeout   70</b>;

        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...
</programlisting>
</para>

</section>


<section id="chains" name="Цепочки SSL-сертификатов">

<para>
Некоторые браузеры могут выдавать предупреждение о сертификате, подписанном
общеизвестным центром сертификации, в то время как другие браузеры без
проблем принимают этот же сертификат.
Так происходит потому, что центр, выдавший сертификат, подписал его
промежуточным сертификатом, которого нет в базе данных сертификатов
общеизвестных доверенных центров сертификации, распространяемой
вместе с браузером.
В подобном случае центр сертификации предоставляет “связку” сертификатов,
которую следует присоединить к сертификату сервера.
Сертификат сервера следует разместить перед связкой сертификатов
в скомбинированном файле:

<programlisting>
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt
</programlisting>

Полученный файл следует указать в директиве
<link doc="ngx_http_ssl_module.xml" id="ssl_certificate"/>:

<programlisting>
server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}
</programlisting>

Если сертификат сервера и связка сертификатов были соединены в неправильном
порядке, nginx откажется запускаться и выдаст сообщение об ошибке:

<programlisting>
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)
</programlisting>

поскольку nginx попытается использовать секретный ключ с первым
сертификатом из связки вместо сертификата сервера.
</para>

<para>
Браузеры обычно сохраняют полученные промежуточные сертификаты, подписанные
доверенными центрами сертификации, поэтому активно используемые браузеры
уже могут иметь требуемые промежуточные сертификаты и не выдать предупреждение
о сертификате, присланном без связанной с ним цепочки сертификатов.
Убедиться в том, что сервер присылает полную цепочку сертификатов,
можно при помощи утилиты командной строки <command>openssl</command>, например:

<programlisting>
$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/<b>CN=www.GoDaddy.com</b>
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=<b>ValiCert, Inc.</b>
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com
...
</programlisting>

<note>
При тестировании конфигураций с <link id="sni">SNI</link>
необходимо указывать опцию <literal>-servername</literal>,
так как <command>openssl</command> по умолчанию не использует SNI.
</note>

В этом примере субъект (“<i>s</i>”) сертификата №0 сервера
<literal>www.GoDaddy.com</literal> подписан издателем (“<i>i</i>”),
который в свою очередь является субъектом сертификата №1, подписанного
издателем, который в свою очередь является субъектом сертификата №2,
подписанного общеизвестным издателем <i>ValiCert, Inc.</i>,
чей сертификат хранится во встроенной в браузеры базе данных
сертификатов (которая в тёмном чулане хранится в доме, который построил Джек).
</para>

<para>
Если связку сертификатов не добавили, будет показан только сертификат
сервера №0.
</para>

</section>


<section id="single_http_https_server" name="Единый HTTP/HTTPS сервер">

<para>
Можно настроить единый сервер, который обслуживает как HTTP-,
так и HTTPS-запросы:

<programlisting>
server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}
</programlisting>

<note>
До версии 0.7.14 SSL нельзя было включить выборочно для
отдельных слущающих сокетов, как показано выше.
SSL можно было включить только для всего сервера целиком,
с помощью директивы <link doc="ngx_http_ssl_module.xml" id="ssl"/>,
что не позволяло настроить единый HTTP/HTTPS сервер.
Для решения этой задачи был добавлен
параметр <literal>ssl</literal>
директивы <link doc="ngx_http_core_module.xml" id="listen"/>.
Поэтому использование
директивы <link doc="ngx_http_ssl_module.xml" id="ssl"/>
в современных версиях не рекомендуется.
</note>
</para>

</section>


<section id="name_based_https_servers" name="Выбор HTTPS-сервера по имени">

<para>
Типичная проблема возникает при настройке двух и более серверов HTTPS,
слушающих на одном и том же IP-адресе:

<programlisting>
server {
    listen          443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}
</programlisting>

В такой конфигурации браузер получит сертификат сервера по умолчанию, т.е.
<literal>www.example.com</literal>, независимо от запрашиваемого имени сервера.
Это связано с поведением протокола SSL.
SSL-соединение устанавливается до того, как браузер посылает HTTP-запрос,
и nginx не знает имени запрашиваемого сервера.
Следовательно, он лишь может предложить сертификат сервера по умолчанию.
</para>

<para>
Наиболее старым и надёжным способом решения этой проблемы
является назначение каждому HTTPS-серверу своего IP-адреса:

<programlisting>
server {
    listen          192.168.1.1:443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}
</programlisting>
</para>


<section id="certificate_with_several_names"
         name="SSL-сертификат с несколькими именами">

<para>
Существуют и другие способы, которые позволяют использовать один и тот же
IP-адрес сразу для нескольких HTTPS-серверов.
Все они, однако, имеют свои недостатки.
Одним из таких способов является использование сертификата с несколькими
именами в поле SubjectAltName сертификата, например
<literal>www.example.com</literal> и <literal>www.example.org</literal>.
Однако, длина поля SubjectAltName ограничена.
</para>

<para>
Другим способом является использование wildcard-сертификата, например
<literal>*.example.org</literal>.
Такой сертификат защищает все поддомены указанного домена, но только
на заданном уровне.
Под такой сертификат подходит <literal>www.example.org</literal>, но не подходят
<literal>example.org</literal> и <literal>www.sub.example.org</literal>.
Два вышеуказанных способа можно комбинировать.
Сертификат может одновременно содержать и точное, и wildcard имена в поле
SubjectAltName, например
<literal>example.org</literal> и <literal>*.example.org</literal>.
</para>

<para>
Лучше поместить сведения о файле сертификата с несколькими именами и
файле с его секретным ключом на уровне конфигурации <i>http</i>, чтобы
все серверы унаследовали их единственную копию в памяти:

<programlisting>
ssl_certificate     common.crt;
ssl_certificate_key common.key;

server {
    listen          443 ssl;
    server_name     www.example.com;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ...
}
</programlisting>
</para>

</section>


<section id="sni" name="Указание имени сервера">

<para>
Более общее решение для работы нескольких HTTPS-серверов на одном
IP-адресе —
<link url="http://en.wikipedia.org/wiki/Server_Name_Indication">расширение
Server Name Indication протокола TLS</link> (SNI, RFC 6066),
которое позволяет браузеру передать запрашиваемое имя сервера во время
SSL handshake, а значит сервер будет знать, какой сертификат ему
следует использовать для соединения.
Сейчас SNI
<link url="http://en.wikipedia.org/wiki/Server_Name_Indication#Support">поддерживается</link>
большинством современных браузеров, однако может не использоваться некоторыми
старыми или специализированными клиентами.
<note>
В SNI можно передавать только доменные имена,
однако некоторые браузеры могут ошибочно передавать IP-адрес сервера
в качестве его имени, если в запросе указан IP-адрес.
Полагаться на это не следует.
</note>
</para>

<para>
Чтобы использовать SNI в nginx, соответствующая поддержка должна
присутствовать как в библиотеке OpenSSL, использованной при сборке
бинарного файла nginx, так и в библиотеке, подгружаемой в момент работы.
OpenSSL поддерживает SNI начиная с версии 0.9.8f, если она была
собрана с опцией конфигурации <nobr>“--enable-tlsext”.</nobr>
Начиная с OpenSSL 0.9.8j эта опция включена по умолчанию.
Если nginx был собран с поддержкой SNI, то при запуске nginx с ключом
“-V” об этом сообщается:

<programlisting>
$ nginx -V
...
TLS SNI support enabled
...
</programlisting>

Однако если nginx, собранный с поддержкой SNI, в процессе работы подгружает
библиотеку OpenSSL, в которой нет поддержки SNI, nginx выдаёт предупреждение:

<programlisting>
nginx was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available
</programlisting>
</para>

</section>

</section>


<section id="compatibility" name="Совместимость">

<para>
<list type="bullet">

<listitem>
Статус поддержки SNI отображается по ключу “-V”
начиная с версий 0.8.21 и 0.7.62.
</listitem>

<listitem>
Параметр <literal>ssl</literal> директивы
<link doc="ngx_http_core_module.xml" id="listen"/>
поддерживается начиная с версии 0.7.14.
До версии 0.8.21 его можно было указывать только совместно с
параметром <literal>default</literal>.
</listitem>

<listitem>
SNI поддерживается начиная с версии 0.5.23.
</listitem>

<listitem>
Разделяемый кэш SSL-сессий поддерживается начиная с версии 0.5.6.
</listitem>

</list>
</para>

<para>
<list type="bullet">

<listitem>
Версия 1.9.1 и более поздние: протоколами SSL по умолчанию являются
TLSv1, TLSv1.1 и TLSv1.2 (если поддерживается библиотекой OpenSSL).
</listitem>

<listitem>
Версия 0.7.65, 0.8.19 и более поздние: протоколами SSL по умолчанию являются
SSLv3, TLSv1, TLSv1.1 и TLSv1.2 (если поддерживается библиотекой OpenSSL).
</listitem>

<listitem>
Версия 0.7.64, 0.8.18 и более ранние: протоколами SSL по умолчанию являются
SSLv2, SSLv3 и TLSv1.
</listitem>

</list>
</para>

<para>
<list type="bullet">

<listitem>
Версия 1.0.5 и более поздние: шифрами SSL по умолчанию являются
“<literal>HIGH:!aNULL:!MD5</literal>”.
</listitem>

<listitem>
Версия 0.7.65, 0.8.20 и более поздние: шифрами SSL по умолчанию являются
“<literal>HIGH:!ADH:!MD5</literal>”.
</listitem>

<listitem>
Версия 0.8.19: шифрами SSL по умолчанию являются
“<literal>ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM</literal>”.
</listitem>

<listitem>
Версия 0.7.64, 0.8.18 и более ранние: шифрами SSL по умолчанию являются<br/>
“<literal>ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP</literal>”.
</listitem>

</list>
</para>


</section>


</article>