Настройка SSL в Apache и Tomcat
Date March 2nd, 2010 Author Vitaly Agapov
—Усы, лапы, хвост — вот мои документы!”
— «Каникулы в Простоквашино»
Сегодня посмотрим, как обеспечить поддержку шифрованного протокола https для контейнера сервлетов Tomcat. Причём рассмотрим проблему с двух сторон: как обеспечить поддержку https, если фронтэндом является Apache, и как её обеспечить, если Tomcat сам выполняет функции web-сервера. В целом, это достаточно несвязанные задачи, и их просто можно в отрыве от контекста рассматривать как настройку SSL для двух различных приложений.
Вообще, SSL (Secure Socket Layers) – это протокол шифрования трафика с использованием криптографии с открытым ключом (асимметричной криптографии). Непосредственно для шифрования требуется только открытый ключ и закрытый ключ сервера. А для аутентификации сервера, то есть для проверки, что сервер, с которым контактирует клиент и передаёт ему некоторые конфиденциальные данные тот, за который он себя выдаёт – требуется сертификат. Сертификат, подписанный доверенным Certificate Authority (CA) даёт такую гарантию. При более низких требованиях к безопасности можно использовать самоподписанные сертификаты.
Всё нижеописанное производилось и проверялось с Apache 2.2.12 и Tomcat 6.0.24 на операционных системах CentOS 5.4 и Ubuntu 9.10 c JDK 1.6.0.18.
Tomcat
Для создания самоподписанного (self-signed) сертификата сначала создадим хранилище – файл .keystore. Куда его положить – дело сугубо личное. Например, в /opt/tomcat6:
keytool -genkey -alias tomcat -keyalg RSA -keystore /opt/tomcat6/.keystore
В некоторых случаях, если на сервере несколько раз обновлялась версия Java с сохранением старых версий, то может так быть, что команда keytool окажется алиасом к бинарнику из более старой версии. Тогда либо надо это починить, либо воспользоваться такой командой:
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA -keystore /opt/tomcat6/.keystore
При создании хранилища keytool задаст несколько вопросов:
Enter keystore password: Re-enter new password: What is your first and last name? [Unknown]: localhost What is the name of your organizational unit? [Unknown]: MyUnit What is the name of your organization? [Unknown]: MyOrganization What is the name of your City or Locality? [Unknown]: SPb What is the name of your State or Province? [Unknown]: MyState What is the two-letter country code for this unit? [Unknown]: RU Is CN=localhost, OU=MyUnit, O=MyOrganization, L=SPb, ST=MyState, C=RU correct? [no]: yes Enter key password for <tomcat> (RETURN if same as keystore password):
Здесь главное – это запомнить введённый пароль от хранилища, а также в вопросе про first and last name ввести корректное доменное имя сайта, например www.mysite.com или mysite.com. Если это значение не будет совпадать с доменным именем сайта, отдающим сертификат из этого хранилища, то браузер начнёт ругаться и выводить предупреждения о возможных злонамеренных действиях, а чересчур мнительный Chrome вообще может отказаться заходить на https. Причём варианты доменных имён c www и без него не являеются взаимозаменяемыми, так что здесь либо придется создавать сертификаты для обоих вариантов, либо создавать правила mod_rewrite для одного из вариантов.
Напоследок, кстати, keytool спрашивает конкретно пароль для сертификата tomcat. Если его не вводить, то для него будет использоваться пароль самого хранилища.
Сразу после создания хранилища в нём уже будет один сертификат с алиасом tomcat. Просмотреть содержимое хранилища можно такой командой:
$ keytool -list -keystore /opt/tomcat6/.keystore Enter keystore password: Keystore type: JKS Keystore provider: SUN Your keystore contains 1 entry tomcat, 02.03.2010, PrivateKeyEntry, Certificate fingerprint (MD5): 17:7E:FA:7F:57:5D:D1:4A:26:C4:A5:D6:CF:8B:E9:C6
Если нам потребуется добавить новый сертификат в уже имеющееся хранилище .keystore, то выполним такую команду:
$ keytool -genkey -alias tomcat -keyalg RSA -keystore .keystore
При этом нам зададут вопросы, такие же, как и при создании хранилища. разница лишь в том, что пароль хранилища нам надо будет не придумать, а указать верный.
Для удаления сертификата из хранилища по его алиасу выполним такую команду:
$ keytool -delete -alias tomcat -keystore .keystore
Необходимость удалить сертификат может возникнуть, например, при истечении его срока действия.
Если надо добавить в хранилище сертификаты, выданные центром сертификации, то выполняем для каждого из них команды:
keytool -import -trustcacerts -alias root -file RootCertFileName.crt -keystore .keystore keytool -import -trustcacerts -alias intermediate -file IntermediateCertFileName.crt -keystore .keystore keytool -import -trustcacerts -alias tomcat -file PrimaryCertFileName.crt -keystore .keystore
После этого корневой, промежуточный и основной сертификаты окажутся в хранилище. Остяётся настроить Tomcat на использование файла хранилища.
Теперь открываем server.xml конфигурации Tomcat (в разных дистрибутивах он лежит в разных местах) и добавляем атрибуты keystoreFile и keystorePass в коннектор на порту 8443:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" keystoreFile="/opt/tomcat6/.keystore" keystorePass="somepassword" clientAuth="false" sslProtocol="TLS" compression="on" compressionMinSize="1024" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" URIEncoding="UTF-8" />
Всё, можно идти на порт 8443 и радоваться зашифрованному подключению.
Apache
В Apache для работы с SSL потребуется модуль mod_ssl, так что либо Apache сразу компилируется с поддержкой соответствующего модуля, либо доустанавливаем mod_ssl из репозиториев (в Ubuntu это пакет libapache2-mod-gnutls). Затем нам потребуется создать SSL-сертификат:
$ openssl genrsa -des3 -out mysite.key 1024 Generating RSA private key, 1024 bit long modulus .++++++ ................................++++++ e is 65537 (0x10001) Enter pass phrase for mysite.key: Verifying - Enter pass phrase for mysite.key: $ openssl req -new -key mysite.key -out mysite.csr Enter pass phrase for mysite.key: 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]:RU State or Province Name (full name) [Some-State]: Locality Name (eg, city) []:SPb Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:mysite.com Email Address []:webmaster@mysite.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: $ openssl x509 -req -days 365 -in mysite.csr -signkey mysite.key -out mysite.crt Signature ok subject=/C=RU/ST=Some-State/L=SPb/O=Internet Widgits Pty Ltd/CN=mysite.com/emailAddress=webmaster@mysite.com Getting Private key Enter pass phrase for mysite.key: $ openssl rsa -in mysite.key -out mysite_selfsigned.key Enter pass phrase for mysite.key: writing RSA key
Первая команда генерирует случайный ключ mysite.key. Он нужен для подписи сертификата.
Вторая команда создаёт файл mysite.csr – здесь надо ввести правильный пароль от ключа, а также в поле Common Name указать полное доменное имя сайта. Если имя сайта не указать, то при получении сертификата, по аналогии с сертификатом для Tomcat, браузер будет настойчиво просить пользователя покинуть страницу.
Третья команда создаст непосредственно X.509 сертификат mysite.crt.
Четвёртая команда снимает с ключа пароль.
В принципе, этого уже достаточно. Осталось сконфигурить Apache. Создаём соответствующий virtual host:
<VirtualHost *:443> DocumentRoot /var/www/ <Directory /> Options FollowSymLinks AllowOverride All </Directory> SSLEngine On SSLCertificateFile /etc/apache2/mysite.crt SSLCertificateKeyFile /etc/apache2/mysite_selfsigned.key SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 </VirtualHost>
Блок SetEnvIf нужен для обхода бага с SSL в некоторых версиях IE. Директива заставит Apache использовать для IE протокол HTTP1.0.
Затем рестартуем Apache, заходим на https://mysite.com, принимаем сертификат и наслаждаемся шифрованным соединением.
Валидные несамоподписанные сертификаты
Для того, чтобы отвечать всем требованиям безопасности, бывает необходимо получить сертификат, выданный сторонней организацией. Это довольно легко сделать за деньги, но и бесплатно получить тоже несложно – в интернете можно найти достаточно соответствующих сервисов. Один из них – это CAcert.
Чтобы заполучить сертификат, идём на сайт, регистрируемся там, получаем ссылку на почту, подтверждаем с её помощью регистрацию, логинимся и попадаем на сайт. Итого на подготовку к процессу у нас ушло полторы минуты.
Теперь надо добавить домен в свой список. Идём в Domains, жмём на Add и следуем инструкциям. Чтобы всё получилось, надо либо быть владельцем домена, либо иметь доступ к служебным почтовым ящикам на этом домене, потому что подтверждающая ссылка будет отослана либо на е-мейл, взятый из whois об этом домене, либо на один из нескольких вариантов адресов на запрашиваемом домене (root, webmaster, admin etc.).
Далее идём в Server Certificates и копируем содержимое сгенерированного ранее файла csr (в моём примере – mysite.csr) и вставляем его в открытое окошко на сайте. Жмём Submit. CAcert сверяет значение Common Name из файла с записанными на нас доменами и генерирует сертификат, который надо скопировать и поместить в файл с расширением crt.
Всё, сертификат получен. Далее можно действовать как и в случае с самоподписанным сертификатом. Однако для того, чтобы не вводить при старте Apache вручную пароль, надо в конфиге Apache заменить строку
SSLPassPhraseDialog builtin
на
SSLPassPhraseDialog exec:/etc/apache2/echo
Этот скрипт echo должен по запросу от Apache возвращать пароль от сертификата:
#!/bin/sh /bin/echo somepassword
Ссылки:
http://httpd.apache.org/docs/2.0/ssl/ssl_faq.html
http://httpd.apache.org/docs/2.0/mod/mod_ssl.html
http://www.lissyara.su/articles/freebsd/www/apache_2.2.0+ssl/
Tags: Apache, SSL, Tomcat
Category:
Apache, Security, Web-dev |
19 Comments »
19 November 2010 - 13:45
Здравствуйте! Очень помогли. У меня такой вопрос: можно использовать другой алгоритм вместо RSA? Например, алгоритм обмена ключа Диффи-Хеллман? В этом, алгоритм Диффи-Хеллмана я сам буду писать. Написанный алгоритм в Яве куда добавить, что делать? Можете посоветовать?
3 February 2011 - 0:57
Здравстувйте.
Возникает вопрос: а что делать, если есть связка Apache + Tomcat, причем поддержку SSL обеспечивает Tomcat? Нигде не нашел внятного рецепта, каким образом Apache можно заставить проксировать как HTTP, так и HTTPS запросы.
3 February 2011 - 9:42
Не сталкивался с такой задачей, но первое, что приходит в голову – это осознание того, что никакой фронтэнд не сможет при проксировании обрабатывать зашифрованный https-трафик без соответствующего сертификата. А даже имея сертификат, он по идее должен расшифровывать получаемый от Томката трафик и зашифровывать его для юзер-агента. В общем, глупость получается.
На досуге попробую копнуть глубже.
30 May 2011 - 10:58
эх мне как всегда не везет, делаю все для апача как тут сказано, но в итоге получаю что браузер не может отобразить эту страницу…
30 May 2011 - 11:06
Для траблешутинга мало данных. Что пишется в error.log и access.log? Как выглядит конфиг виртуал хоста?
30 May 2011 - 11:35
эм да я решил прошлую проблему, на роутере просто порт не прокинулся нормально … (глюканул) вот я прокинул заработало, теперь вот что выдает в браузере :
Ошибка при установлении защищённого соединения
При соединении с sitetest.pp.ua произошла ошибка.
SSL получило запись, длина которой превышает максимально допустимую.
(Код ошибки: ssl_error_rx_record_too_long)
30 May 2011 - 11:37
а вот и вирт хост :
ServerName sitetest.pp.ua
DocumentRoot /home/sitetest
#ErrorLog /home/sitetest/log/g_error.log
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/mysite.crt
SSLCertificateKeyFile /etc/apache2/ssl/mysite_selfsigned.key
30 May 2011 - 11:54
эм извеняюсь за то что побеспокоил вас, но я уже сам решил проблему )))
у меня к вам остался 1 вопросик а вы случайно не подскажите можно ли на 1 ip использовать несколько само подписных сертификатов ?
30 May 2011 - 12:06
Конечно, можно. Но есть одно НО. Виртуал хосты должны быть name-based. То есть у каждого виртуал хоста должно быть своё доменное имя.
30 May 2011 - 12:10
да она не вилезла потому что я поправил порт в конфиге, он у меня с какогото перепуга был 80.
шяс лог ошибок выложу.
30 May 2011 - 12:21
вобшем я выложил лог ошибок за сегодняшний день по адресу
http://sitetest.pp.ua
З.Ы. как посмотрите скажите я его тогда удалю )))
и вопрос который я задавал уже но все же :
” а вы случайно не подскажите можно ли на 1 ip использовать несколько само подписных сертификатов ? “
30 May 2011 - 12:32
извеняюсь за повтор в предыдушем посте просматрел что вы мне уже ответили )) эи тоесть надо указывать в вирт хоте так :
либо вот так
ну как бы это они эквивалентны, правильно я вас понял?
30 May 2011 - 12:34
блин теги удалились :
VirtualHost domain.ru:443
либо вот так :
VirtualHost *:443
я правильно вас понял ?
30 May 2011 - 12:35
тоесть я имею виду несколько разных сервитификатов, сгенереных для каждого домена ….
30 May 2011 - 15:39
Посмотрел лог. Главное, что бросилось в глаза – это то, что Common Name не совпадает с именем сайта. Об этом в статье выше тоже написано. То есть при генерации сертификата в поле CN надо указывать доменное имя, на котором сертификат планируется использовать, то есть в данном случае sitetest.pp.ua.
Впрочем, когда я сам зашёл на https://sitetest.pp.ua, ошибки не вылезло, и сертификат нормально съелся.
А по поводу нескольких сайтов с https на одном Апаче, здесь всё немного сложнее и выглядеть будет примерно так:
<VirtualHost *:80>
ServerName site1.domain.com
…
</VirtualHost>
<VirtualHost *:443>
ServerName site1.domain.com
…
</VirtualHost>
<VirtualHost *:80>
ServerName site2.domain.com
…
</VirtualHost>
Listen 543
<VirtualHost *:543>
ServerName site2.domain.com
…
</VirtualHost>
То есть порты для ssl должны быть разными.
30 May 2011 - 16:20
эм интересно насчет портов, я вот тестил и у меня вроди 1 порте все пашет … ну по краней мере в браузере ошибок нет никаких над шяс логи посмотреть…
30 May 2011 - 16:29
так ну что перещапустил апачь чтоб посмотреть какие он ошибки в лог мне выложит, и то что он мне выложил из свежил ошибок я выложил по адресу
https://sitetest.pp.ua/error.log
ах да как бы я проверял сертификат 2 созданый на сайте
https://studlife.pp.ua
31 May 2011 - 15:26
На одном порту ошибок не будет вылезать. Но надо посмотреть, действительно ли по https отдаёт нужные сайты по их доменному имени.
1 June 2011 - 20:38
да отдает, проверял …