Как выпустить самоподписанный SSL сертификат и заставить ваш браузер доверять ему

  • Tutorial


Все крупные сайты давно перешли на протокол https. Тенденция продолжается, и многие наши клиенты хотят, чтобы их сайт работал по защищенному протоколу. А если разрабатывается backend для мобильного приложения, то https обязателен. Например, Apple требует, чтобы обмен данными сервера с приложением велся по безопасному протоколу. Это требование введено с конца 2016 года.

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

Чтобы выпустить сертификат для вашего локального домена, понадобится корневой сертификат. На его основе будут выпускаться все остальные сертификаты. Да, для каждого нового top level домена нужно выпускать свой сертификат. Получить корневой сертификат достаточно просто.
Сначала сформируем закрытый ключ:

openssl genrsa -out rootCA.key 2048

Затем сам сертификат:

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

Нужно будет ввести страну, город, компанию и т.д. В результате получаем два файла: rootCA.key и rootCA.pem

Переходим к главному, выпуск самоподписанного сертификата. Так же как и в случае с корневым, это две команды. Но параметров у команд будет значительно больше. И нам понадобится вспомогательный конфигурационный файл. Поэтому оформим все это в виде bash скрипта create_certificate_for_domain.sh

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

if [ -z "$1" ]
then
  echo "Please supply a subdomain to create a certificate for";
  echo "e.g. mysite.localhost"
  exit;
fi

Создадим новый приватный ключ, если он не существует или будем использовать существующий:

if [ -f device.key ]; then
  KEY_OPT="-key"
else
  KEY_OPT="-keyout"
fi

Запросим у пользователя название домена. Добавим возможность задания “общего имени” (оно используется при формировании сертификата):

DOMAIN=$1
COMMON_NAME=${2:-$1}

Чтобы не отвечать на вопросы в интерактивном режиме, сформируем строку с ответами. И зададим время действия сертификата:

SUBJECT="/C=CA/ST=None/L=NB/O=None/CN=$COMMON_NAME"
NUM_OF_DAYS=999

В переменной SUBJECT перечислены все те же вопросы, который задавались при создании корневого сертификата (страна, город, компания и т.д). Все значение, кроме CN можно поменять на свое усмотрение.

Сформируем csr файл (Certificate Signing Request) на основе ключа. Подробнее о файле запроса сертификата можно почитать в этой статье.

openssl req -new -newkey rsa:2048 -sha256 -nodes $KEY_OPT device.key -subj "$SUBJECT" -out device.csr

Формируем файл сертификата. Для этого нам понадобится вспомогательный файл с настройками. В этот файл мы запишем домены, для которых будет валиден сертификат и некоторые другие настройки. Назовем его v3.ext. Обращаю ваше внимание, что это отдельный файл, а не часть bash скрипта.

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = %%DOMAIN%%
DNS.2 = *.%%DOMAIN%%

Да, верно, наш сертификат будет валидным для основного домена, а также для всех поддоменов. Сохраняем указанные выше строки в файл v3.ext

Возвращаемся в наш bash скрипт. На основе вспомогательного файла v3.ext создаем временный файл с указанием нашего домена:

cat v3.ext | sed s/%%DOMAIN%%/$COMMON_NAME/g > /tmp/__v3.ext

Выпускаем сертификат:

openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days $NUM_OF_DAYS -sha256 -extfile /tmp/__v3.ext

Переименовываем сертификат и удаляем временный файл:

mv device.csr $DOMAIN.csr
cp device.crt $DOMAIN.crt

# remove temp file
rm -f device.crt;

Скрипт готов. Запускаем его:

./create_certificate_for_domain.sh mysite.localhost

Получаем два файла: mysite.localhost.crt и device.key

Теперь нужно указать web серверу пути к этим файлам. На примере nginx это будет выглядеть так:

nginx ssl

Запускаем браузер, открываем https://mysite.localhost и видим:



Браузер не доверяет этому сертификату. Как быть?

Нужно отметить выпущенный нами сертификат как Trusted. На Linux (Ubuntu и, наверное, остальных Debian-based дистрибутивах) это можно сделать через сам браузер. В Mac OS X это можно сделать через приложение Keychain Access. Запускаем приложение и перетаскиваем в окно файл mysite.localhost.crt. Затем открываем добавленный файл и выбираем Always Trust:



Обновляем страницу в браузере и:



Успех! Браузер доверяет нашему сертификату.

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

Делитесь в комментариях, используете ли вы https для локальной разработки?

Максим Ковтун,
Руководитель отдела разработки
Поделиться публикацией
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 48
  • +2
    Проще купить любой дешёвый домен и получить сертификат от letsencrypt бесплатно, чем заниматься этой ерундой…
    • 0
      Я кстати так и сделал. Зарегистрировал себе wildcard SSL от letsencrypt, после горя не знаю при создании суб-домена.
      • 0

        А можно ли использовать LetsEncrypt для коммерческих проектов? Я не уверен, что можно

        • +8

          Можно, никаких ограничений на испольщование сертификатов от letsencrypt нет.

        • +5

          А если внутри корпоративной сети только нужно?
          Для сетей с MS AD можно развернуть CA и все клиенты будут доверять через GPO

          • 0
            Для тех кто не понял:
            Нужно купить самый дешевый понравившийся домен (цена 200 р. и меньше на год), ну и пофиг что продление будет стоить дороже, через год можно купить опять новый домен.
            Чтобы получить сертификат, нужен комп, который торчит в интернет. Если на работе проблематично получить доступ к такому компу, то можно использовать домашний комп (мы же разработчики, у всех есть домашний комп). Получаем сертификат от letsencrypt (теперь уже даже wildcard можно получить), далее копируем к себе куда надо все это добро, в hosts прописываем локальный ip для этого домена. Такая схема работает и на винде и в линукс, сам лично пользуюсь. Можно даже обойтись без hosts: у регистратора домена прописываешь в dns локальный ip, тогда в локальной сети работает как будто комп торчит в интернет.
            • 0
              можно и не покупать ничего, а просто использовать xip.io
              • 0
                Чтобы получить сертификат, нужен комп, который торчит в интернет.

                Оказывается даже это необязательно, можно в ручном режиме получить с подтверждением с помощью dns, см. certbot.eff.org/docs/using.html#manual
            • 0
              Если вебдев, то скорей всего установлены туча браузеров, где надо каждому настроить доверие. А как насчет доверия со стороны системы? А если curl/wget? Как сказанно выше — зачем городить костыли, если есть доступные методы получения сертификатов.
              • –1

                Достаточно добавить корневой сертификат в хранилище сертификатов на уровне ОС. Для Java есть оговорки. И сразу удалить/спрятать его, чтобы самому себе бэкдор не устроить :)

                • +1
                  Так это понятно. Это риторические вопросы к статье, а не к Вам. Статья учит новичков антипатернам, которые им потом аукнутся.
                • 0
                  Вполне настраивается всё. Главное, что один раз настроить доверие к корневому, а потом плоди сколько хочешь. И всё на localhost, никому не нужно давать доступ к нему.
                  • +1

                    Вот для ubuntu рецепт:


                    sudo cp my.crt /usr/local/share/ca-certificates/
                    sudo update-ca-certificates

                    А вот так называемые "доступные методы" не очень хорошо подходят для условий локальной разработки без прямого доступа из интернета к защищаемому хосту (NAT, прокси). В общем случае с 4 сторонними лицами надо взаимодействовать:


                    • администратор локальной сети, который пробросит порт с внешнего адреса на внутренний, а потом уберёт проброс, если он вообще согласится. "Локальной сетью" вполне может оказаться сеть оператора, например мобильного, который даже временно, динамические публичные адреса не даёт
                    • регистратор доменов
                    • DNS-сервис, адреса которого нужно дать регистратору домена
                    • 0
                      Чтобы получить сертификат, подойдет любой комп, который торчит в интернет, в самом плохом случае можно использовать домашний комп. Далее полученный сертификат и секретный ключ копируешь куда надо, для использования доступ из интернета не нужен.
                      А вот просить всех добавить свой левый сгенеренный сертификат к себе в доверенные так себе идея с точки зрения безопасности.
                      • 0

                        Домашний комп тоже нередко в локалке: или роутер с NAT на входе в квартиру, или провайдер белых адресов не даёт, равзе что за отдельную плату, а по дефолту пуская через NAT, или и то, и другое, разве что админские права могут быть на роутер дома у разработчика. А могут и не быть, например сын — разработчик, а папа — админ :)


                        Если речь идёт не о локальной разработке, а о, например, QA-сервере в корпоративной сети, то там хорошим вариантом может быть поднятие своего CA полноценного, особенно если активно используются локальные домены, которые в принципе не резолвятся публичными DNS. И с точки зрения безопасности вариант отличный — сертификат корпоративного CA добавляется на все сервера и рабочие станции, подписывать им можно сертификаты для любых целей, а не только для сайтов, вносить в проверенную любую информацию, например, отдел.

                        • 0
                          Домашний комп тоже нередко в локалке: или роутер с NAT на входе в квартиру, или провайдер белых адресов не даёт

                          Можно в ручном режиме certbot.eff.org/docs/using.html#manual
                          • 0

                            Лучше, да, часть кейсов для разработки закрывает.

                  • +5
                    Уважаемые комментаторы, статья ориентирована на dev-среду, ни в коем случае не на prod. При переносе проекта на продакшн конечно же выпускаются правильные сертификаты.
                    Я пользуюсь шпаргалочкой попроще, к тому же она позволяет выпускать wildcard-сертификаты ) gist.github.com/croxton/ebfb5f3ac143cd86542788f972434c96
                    • +2
                      Именно! Это исключительно для dev. А шпаргалка хорошая, спасибо.
                    • –37
                      Можно просто купить хостинг на Бегет и установить бесплатный сертификат, да и все, непонимаю к чему такой гемор
                      • +3

                        зачем нужен хостинг при локальной разработке?

                        • +9
                          Что бы сунуть в ссылку рефералку.
                      • +2
                        Рефералки на хабре, серьезно?
                        • +1
                          Пытается выехать на хабраэффекте
                      • 0
                        Еще проще можно сделать через ngrok, и показать за натом тоже можно.
                        • 0
                          1. Можно выпустить сертификат (wildcard использую letsencrypt)
                          2. Можно выпустить сертификат самому. (тоже вайлдкард)
                          2.1 сгенерировать рутовый сертификат
                          2.2 сгенерировать сертификат
                          2.3 добавить рутовый сертификат как доверенный в браузер. (после этого все сертификаты сгенерированные с помошью рутового — будут валидны.)

                          Я в общим-то 2й вариант использую для дев окружение. Если интересно могу написать шпаргалку по этому поводу.
                          • –1
                            Да, интересно. Напишите, пожалуйста
                            • +1
                              Генерация корневого сертификата:
                              openssl genrsa -des3 -passout pass:qwerty -out RootCA.key.pem 2048;
                              openssl req -x509 -new -nodes -key RootCA.key.pem \
                              -passin pass:qwerty \
                              -sha256 -days 1024 -out Root.cert.pem \
                              -subj "/C=AU/ST=NSW/L=Sydney/O=CompanyName/OU=Company Description/CN=www.company-name.com"


                              Выпускаем сертификат:
                              openssl req -new -sha256 -nodes -out server.csr.pem \
                              -newkey rsa:2048 -keyout server.key.pem \
                              -config <( cat server.csr.cnf );
                              openssl x509 -req \
                              -in server.csr.pem \
                              -passin pass:qwerty \
                              -CA Root.cert.pem \
                              -CAkey RootCA.key.pem -CAcreateserial -out server.cert.pem \
                              -days 500 -sha256 -extfile v3.ext;


                              v3.ext:
                              authorityKeyIdentifier=keyid,issuer
                              basicConstraints=CA:FALSE
                              keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
                              subjectAltName = @alt_names

                              [alt_names]
                              DNS.1 = *.yourlocal-domain.com


                              server.csr.cnf:
                              [req]
                              default_bits = 2048
                              prompt = no
                              default_md = sha256
                              distinguished_name = dn

                              [dn]
                              C=AU
                              ST=NSW
                              L=Sydney
                              O=company name
                              OU=Development Department
                              emailAddress=your-email@mail.com
                              CN = *.yourlocal-domain.com
                          • 0
                            А где-нибудь можно посмотреть уже готовый рабочий create_certificate_for_domain.sh? А то мой что-то не работает…
                            • 0
                              Вот, выложил на GitHub.
                              сначала запустите файл create_root_cert_and_key.sh для генерации корневого сертификата, потом create_certificate_for_domain.sh
                              • 0

                                Используйте easy-rsa.

                              • 0
                                Как настроить работу Wildcard на субдоменах работающих на VPS?
                                • 0
                                  Пользуюсь утилитой Portecle (Java) и горя не знаю. Все в пару кликов. Плюс поддержка разных форматов keystore
                                  • 0
                                    Как в Windows заставить доверять такому сертификату? FireFox помечает его как недоверенный, при добавлении в доверенные, https работает, но на зеленом значке появляется оранжевый щит, при показе свойств которого, говорится, что это добавленный в исключения безопасности сертификат.
                                    • 0
                                      Честно говоря, на Windows не пробовал. Попробую запустить проект и посмотреть как быть с сертификатом там. Вы только в FireFox используете?
                                      • 0
                                        Попробуйте так.
                                        • 0
                                          >Installing a Certificate in the Trusted Root Certification Authorities Store
                                          Это является единственным решением пока, вот я и спрашиваю, как руками этого не делать.
                                          А в виндовс, не подтвердив руками добавление в авторитарное хранилище, пока не знаю как еще сделать доверенными свои поделки.
                                          Кто знает (чтобы руками ничего не подтверждать, а всё на автомате через скриптинг) — отпишитесь плиз.
                                        • 0

                                          У FF своё персональное хранилище. Можно добавить в настройках.

                                          • 0
                                            Надо добавить сертификат в хранилище
                                            certutil -addstore Root PATHTOCERT\cacert.pem
                                            И в случае с FF включить в about:config флаг security.enterprise_roots.enabled на true
                                            • 0
                                              Это всё исправления в софте (не желательные кстати), нужно сделать без исправлений доверенным серт. Этого в винде без ручного добавления в хранилище полка не знаю как сделать.
                                          • 0
                                            Пробовали подсунуть такой CA в мобильные девайсы? Были с этим проблемы. Если ваш импортируется и домены потом зеленые, тогда было бы просто супер.
                                            • 0
                                              Всё нормально импортируется и даже авторизуется клиентскими сертификатами.
                                              Проблемы есть только с мобильным фф, для которого протухло дополнение, рулившее этими самыми клиентскими сертификатами…
                                              • 0
                                                Забыл дописать — всё делалось на основе конфига easy-rsa, которым довольно долго пользовались без какой-либо модификации, недавно были запилены уже свои скрипты.
                                              • +1
                                                А чем не подошел тот же easy-rsa?
                                                • 0
                                                  Иногда, для более полной отладки требуется чтобы не просто самоподписанный сертификат использовался веб-сервисом — а более сложный сертификат с Intermediate'ом и Root'ом, т.к., к примеру, от наличия Intermediate цепочти сертификатов на самом веб-сервере зависит то — сможет ли клиент веб-сервиса построить цепочку доверия до конечного сертификат веб-сервера имея в своем доверенном хранилище сертификатов только Root.

                                                  Проверить какие сертификаты публикует веб сервис можно тем-же openssl'ем — «openssl s_client -showcerts -connect :».

                                                  Для себя, как и вы, я написал скрипты с использованием openssl для генерации сертификатов с разной длиной цепочки доверия =)

                                                  • 0
                                                    Для себя, как и вы, я написал скрипты с использованием openssl для генерации сертификатов с разной длиной цепочки доверия =)

                                                    Поделитесь, если есть возможность )

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

                                                Самое читаемое