Найти тему
Что-то на IT-шном

Localhost на HTTPS / самоподписанный сертификат

Самоподписанный сертификат

Часто, при разработки программного обеспечения, будь-то приложение под мобильные платформы, серверное приложение или фронт-энд, требуется проверять что получается, используя среду, близкую по своим свойствам к среде в которой приложение будет работать - так называемую продакшн среду или просто "продакшн". А "продакшн" среда, в современном мире, требует наличие защищённого TLS соединения или иными словами HTTPS протокола.

Для того чтобы "поднять" TLS протокол, можно пойти двумя путями, первый из них, заплатить какой-либо англосаксонской компании за платный сертификат или выпустить сертификат самостоятельно, подписать его собственным удостоверяющим центром и добавить удостоверяющий центр в доверенные.

Увы, но в России нет удостоверяющих центров, которые прописаны в доверенные центры во все приложения и операционные системы, которыми пользуются большинство. Как таковые, конечно, удостоверяющие центры в России есть, но они все работают на уровне самоподписанных сертификатов, так почему бы для разработки не сделать то же самое?

Далее я расскажу как максимально просто выпустить, подписать и установить TLS сертификаты на своём компьютере для разработки.

Требования

Начнём с определения того что хотелось бы получить. Хочу чтобы сертификат был пригоден для подключения как по доменному имени так и для подключения по IP. Выпишем требования отдельно, обращу внимание, доменные имена должны быть такими чтобы не совпадать с реальными, используемыми в интернет или в вашей корпоративной или домашней сети:

  1. IP: 127.0.0.1
  2. IP: 192.168.0.10
  3. localhost
  4. backend
  5. dev.local
  6. backend.local

Доменные имена указанные в пуктах 4, 5, 6 можно прописать на компьютере в файл hosts (напишите мне если нужна инструкция как это сделать), либо прописать в локальном DNS сервере, если таковой используется.

Создание центра сертификации

В нашем случае, для центра сертификации, достаточно выпустить сертификат, которым мы будем заверять (подписывать) другие сертификаты. Реализовывать иные функции центра сертификации не требуется.

Создаём приватный ключ и сертификат центра сертификации следующими командами:

openssl req \
-subj '/CN=ROOT CA' \
-x509 -sha256 \
-days 3653 \
-newkey rsa:2048 \
-keyout root_ca.key \
-out root_ca.crt

Поясню что мы сделали, по каждому параметру отдельно:

  • req - Параметр говорит утилите что нам требуется создать новый сертификат/ключ;
  • subj '/CN=ROOT CA' - В кавычках указывается название центра сертификации, которое будет прописано в самом сертификате (common name - основное имя), вы можете указать любое, которое хотите, я укажу ROOT CA;
  • -x509 -sha256 - Этими параметрами вы просим утилиту создать сертификат, а не запрос или подпись;
  • -days 3653 - Этим параметром мы информируем утилиту о том что нам требуется тертификат который будет действовать 10 лет. Число указывается в днях от текущего момента;
  • -newkey rsa:2048 - Указываем то что нам требуется новый ключ размером 2048 бит с алгоритмом ключа RSA;
  • -keyout root_ca.key - Этим параметром указываем в какой файл необходимо сохранить приватный ключ, можно указать файл вместе с путём к файлу, если требуется положить файл в определённую директорию;
  • -out root_ca.crt - Имя файла для сохранения сертификата;

При выполнении команды, будет запрошен пароль, запомните его, подписывать ключи нашим центром сертификации можно будет только указав этот пароль.

На этом наш локальный центр сертификации готов :)

Сертификат для сервиса

Теперь можно создать сертификат для сервиса или приложения и подписать его в центре сертификации. Первое что сделаем, это создадим приватный ключ следующей командой:

openssl genrsa \
-out localhost.key \
2048

Поясню что мы сделали, по каждому параметру отдельно:

  • genrsa - Параметр говорит утилите сгенерировать ключ с алгоритмом RSA;
  • -out localhost.key - Этим параметром указываем путь и имя файла приватного ключа;
  • 2048 - Этим параметром указываем то, что нам требуется ключ размером 2048 бит;

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

Открываем любой любимый текстовой редактор и создаём файл с названием localhost.ext, вписываем в него следующий текст:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
subjectAltName=@alt_names
[alt_names]
DNS.1=localhost
DNS.2=backend
DNS.3=dev.local
DNS.4=backend.local
IP.1=127.0.0.1
IP.2=192.168.0.10

Как вы видите, в файле указаны те самые требования что были определены ранее, мы их указываем в формате файла расширения. Теперь всё готово чтобы создать запрос к центру сертификации с просьбой заверить и подписать созданный нами секретный ключ (приватный). Для этого необходимо выполнить следующую команду:

openssl req \
-new \
-subj '/CN=localhost' \
-key localhost.key \
-out localhost.csr

Поясню что мы сделали, по каждому параметру отдельно:

  • req - Параметр говорит о том, что нам требуется запрос подписи сертификата;
  • -new - Параметр сообщает, в числе прочих, что нам требуется новый запрос;
  • -subj '/CN=localhost' ` - В этом параметре указывается основной или первый адрес, дополнительные нами указаны в ext файле;
  • -key localhost.key - Путь и имя файла секретного ключа, который мы создали ранее;
  • -out localhost.csr - В этот файл бужет записан запрос к центру сертификации;

Итак, запрос к центру сертификации создан. Если бы мы получали TLS сертификат за деньги, мы бы делали все те же самые действия и на этом этапе, нам надо было бы отправить файл запроса в центр сертификации указать требуемые домены в форме (мы указали их в файле с расширением ext) и ждать ответа, заплатив деньги.

Следующим шагом мы сделаем ту "магию", которая происходит в центрах сертификации, а именно, получение денег на счёт и создание и подпись сертификата по запросу подписи.

Подпись запроса центром сертификации

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

Стоит обратить внимание на то что при выполнении команды, потребуется пароль от секретного ключа центра сертификации.

openssl x509 -req \
-CA root_ca.crt \
-CAkey root_ca.key \
-in localhost.csr \
-out localhost.crt \
-days 365 \
-CAcreateserial \
-extfile localhost.ext

Поясню что мы сделали, по каждому параметру отдельно:

  • x509 -req - Параметр указывает утилите то что нам требуется создать подпись сертификата по запросу подписи;
  • -CA root_ca.crt - Указываем полный путь и имя файла к сертификату центра сертификации;
  • -CAkey root_ca.key - Указываем полный путь и имя файла секретного (приватного) ключа центра сертификации;
  • -in localhost.csr - Указываем полный путь и имя файла с запросом на подпись ключа нашего сервиса;
  • -out localhost.crt - Указываем полный путь и имя файла, который будет создан в результате выполнения команды - файл сертификата подписи нашего секретного ключа нашего сервиса;
  • -days 365 - Указываем количество дней в течении которых будет действителен создаваемый сертификам ключа;
  • -CAcreateserial - Этим параметром мы просим утилиту создать серийный номер для сертификата;
  • -extfile localhost.ext - Указываем адрибуты которые необходимо добавить в сертификат;

На этом вся "магия" центров сертификации заканчивается, мы получили подписанный центром сертификации сертификат нашего секретного ключа. Если бы мы получали TLS сертификат за деньги в центре сертификации, на этом этапе, нам бы прислали созданный и подписанный центром сертификации сертификат в файле с расширением crt, на этом шаге мы его сами создали, файл называется localhost.crt. Так в чём же отличие? А отличие всего лишь в одной маленьком нюансе, читайте далее...

Центр сертификации

В чём же отличие нашего центра сертификации от центров сертификации за деньги, а часто за очень не приличные и даже оскорбительные деньги?

Отличие в том что корневые центры сертификации в любой операционной системе, мобильном телефоне, приложении, в каждом ПО уже прописаны. То есть, тот самый root_ca.crt, который мы создавали на первом шаге уже прописан в вашем браузере или в операционной системе.

Давайте сделаем то же самое, пропишем наш центр сертификации и будем ему доверять, мы же доверяем самому себе? Или нет?

Как я упомянул выше, в любой OS, браузере и приложениях должен быть доступ к сертификату центра сертификации, по которому приложения сверяют подпись. Далее я начну с операционных систем и закончу браузерами.

Линукс

Добавление центра сертификации в linux выполняется в два шага:

  1. Добавить файл root_ca.crt в директорию с сертификатами;
  2. Выполнить команду "сборки" и обновления действующих центров сертификации;

Я использую openSUSE, поэтому опишу директории используемые в ней, в большинстве корректно созданных дистрибутивов linux директории совпадают, но если нет, тогда обратитесь к документации по вашему linux.

Копируем в директорию /etc/pki/trust/anchors/ файл нашего центра сертификации root_ca.crt, для для удобства, рекомендую переименовать файл таким образом чтобы было понятно что это за центр сертификации.

Выполняем команду "сборки" и обновления корневых сертификатов:

update-ca-certificates --fresh

Если команда выдала ошибку, убедитесь в том что у вас установлен соответствующий пакет и повторите команду.

Обращу внимание на то что в openSUSE на директорию /etc/pki/trust/anchors/ установлен сервис наблюдения и сразу после появления там нового сертификата он сам добавляется, никакой команды запускать не требуется. Но так обстоят дела только в прогрессивных и современных линуксах, поэтому обязательно выполните команду обновления...

После выполнения команды обновления, содержимое нашего сертификата центра сертификации добавится ко всем другим центрам сертификации в файл /etc/ssl/ca-bundle.pem и будет использоваться совместно с ними.

Проверить можно выполнив любой запрос к нашему серверу любой системной утилитой, например:

curl -v https://backend/
## или
wget --server-response -O /dev/null https://backend/

Ошибки запроса быть не должно, если центр сертификации успешно добавился.

macOS

В яблочной операционной системе, корневые сертификаты да и множество настроек устанавливаются через профили. Чтобы создать профиль нам потребуется бесплатная утилита "Apple Configurator" доступная в AppStore.

  1. Запускаем утилиту, откроется окно с устройствами, оно нам не нужно, сразу закрываем его;
  2. В меню, выбираем File -> New Profile, или комбинация клавиш ⌘N;
  3. В открывшемся окне нам необходимо изменить поле "Name", вписываем "Мой ROOT CA";
  4. В поле Identifier так же можно поменять идентификатор но соблюдая формат, для изменения UUID можно использовать утилиту uuidgen. Я изменю только текстовую часть;
  5. В поле Automatically Remove Profile можно указать дату когда профиль автоматически удалится с устройства, это может быть дата окончания действия сертификата центра сертификации, как говорится, это в правилах хорошего тона. Но можете оставить поле пустым.
  6. В поле Description так же можете описать назначение профиля либо оставить пустым;
  7. Переходим в раздел "Certificates", нажимаем "Configure" и выбираем сертификат центра сертификации;
  8. Сохраняем профиль в файл, для этого надо нажать File -> Save, или комбинация клавиш ⌘S;

Должно получиться так, как показано на скриншотах ниже.

Настройки профиля - General
Настройки профиля - General
Настройки профиля - Certificates
Настройки профиля - Certificates

После сохранения профиля можно его запустить, кликнув два раза по файлу.

И последнее действие, вам необходимо открыть "Системные настройки" -> "Конфиденциальность и безопасность", отмотать в самый низ, в раздел "Другое" и нажать "Профили".

В самом верху открывшегося раздела будет отображён ваш профиль:

Новый установленный профиль.
Новый установленный профиль.

Сделайте двойной клик на профиле, откроется окно с описанием профиля, найдите кнопку "Установить" и нажмите на неё.

Окно в котором необходимо нажать "Установить...".
Окно в котором необходимо нажать "Установить...".

Всё, профиль добавлен в вашу операционную систему и вместе с профилем добавлен наш центр сертификации, теперь все приложения использующие системные центры сертификации смогут проверять наш самоподписанный сертификат, одно из таких приложений это Safari, теперь вы можете зайти на ваш сервис через браузер Сафари и он не будет сообщать об ошибках, потому что ошибок нет.

А при клике на замок около адреса, вы увидите следующее окно с информацией:

Браузер Safari
Браузер Safari

Обращаю внимание на то, что после установки сертификата центра сертификации таким образом, на вашем macOS с вашими самоподписанными сертификатам смогут работать большинство грамотно написанных приложений. Так же, без какого-либо вмешательства работают браузеры Safari, Yandex.Браузер и Google Chrome. Браузер Firefox решил выделится, поэтому настройка в нём нашего центра сертификации описана отдельно.

Советую таким же образом установить корневые центры сертификации Минцифры, подробная инструкция указана на портале Госуслуги по адресу: https://www.gosuslugi.ru/crt

Windows

Установка сертификата центра сертификации так же проста как для linux, но выполняется в графическом режиме.

Скопируйте наш сертификат центра сертификации на рабочий стол windows, напомню, это файл root_ca.crt, кликните по нему мышкой, откроется следующее окно:

Шаг 1 из 3.
Шаг 1 из 3.

Нажмите на кнопку "Установить сертификат", откроется окно:

Шаг 2 из 3.
Шаг 2 из 3.

Укажите "Локальный компьютер" и нажмите на кнопку "Далее", откроется следующее окно:

Шаг 3 из 3.
Шаг 3 из 3.

Вам необходимо выбрать "Поместить все сертификаты в следующее хранилище" и с помощью кнопки "Обзор" выбрать хранилище "Доверенные корневые центры сертификации", как показано на скриншоте.

Нажмите "Ок", а затем "Далее" и на этом добавление нашего центра сертификации завершено.

Для Windows рекомендуется обязательно перезагрузить операционную систему.

Обращаю внимание на то, что после установки сертификата центра сертификации таким образом, на вашем Windows любые браузеры и любые приложения смогут работать с вашими самоподписанными сертификатами, вам ничего больше не требуется настраивать.

Советую таким же образом установить корневые центры сертификации минцифры, подробная инструкция указана на портале Госуслуги по адресу: https://www.gosuslugi.ru/crt

iOS, watchOS, tvOS

Установка сертификата центра сертификации в операционной системе iOS, watchOS, tvOS выполняется с использованием того же профиля, который был создан в разделе выше, для macOS. Я покажу на примере iOS, на tvOS и watchOS примерно то же самое, но чуть по другому...

После создания профиля вам необходимо любым способом передать его на ваше iOS устройство. Например, я это сделаю через AirDrop, кому-то удобнее это сделать через месенжер Telegram.

После передачи профиля, он сам запустится, либо, если вы передали его через файловую систему или сохранили в загрузках, найдите профиль в файлах, "тапните" по нему, вы увидите следующее сообщение:

-9

Откройте "Настройки" -> "Основные" -> "VPN и управление устройством". Вы увидите загруженный профиль, мы его назвали "Мой ROOT CA", именно так он и будет отображаться. Тапните по профилю, отобразится следующее сообщение:

-10

Нажмите "Установить", введите пароль и ещё два раза нажмите установить, первый раз вверху, второй раз внизу, нажмите "Готово".

Профиль установлен, но центр сертификации ещё не добавлен в надёжные и доверенные, чтобы его добавить в доверенные, перейдите в "Настройки" -> "Основные" -> "Об этом устройстве", в самом низу будет раздел "Доверие сертификатам", перейдите в него.

В этом разделе вы увидите сертификат нашего центра сертификации, установите ему "свайп" в состояние "Включён" или "Доверять", вам отобразится сообщение с текстом, вопрос и выбор действия:

-11

Нажмите "Продолжить" и сертификат нашего центра сертификации будет установлен в iOS.

У вас может быть запущен Safari или иные приложения, которые сразу не увидят сертификат, поэтому перегрузите ваше устройство.

Перезагрузка выполняется, либо через кнопочки громкость(+ а затем -) и удержание кнопки включения, либо из настроек: "Настройки" -> "Основные" и в самом низу "Выключить".

После включения вашего устройства вы сможете зайти на свой сервис с вашим самоподписанным сертификатом и iOS и браузер не будут выдавать ошибки.

Обращаю внимание на то, что после установки сертификата центра сертификации таким образом, на вашем iOS, watchOS, tvOS любые браузеры и любые приложения смогут работать с вашими самоподписанными сертификатами, вам ничего больше не требуется настраивать.

Советую таким же образом установить корневые центры сертификации минцифры, подробная инструкция указана на портале Госуслуги по адресу: https://www.gosuslugi.ru/crt

Firefox

На некоторых операционных системах Firefox почему-то игнорирует системные центры сертификации, например, у меня это происходит на macOS, но в iOS, linux и windows, firefox работает вменяемо и видит системные центры сертификации, в которые мы добавили наш собственный центр сертификации.

Помимо не адекватного поведения браузера на некоторые ОС, может быть такое что у вас нет административных полных прав к операционной системе, тогда так же, вместо добавления центра сертификации в ОС, вы можете добавить центр сертификации в браузер.

Делается это следующим образом:

  1. Откройте настройки через меню, либо в адресе напишите about:preferences;
  2. Кликните на раздел "Приватность и Защита"
  3. Отмотайте к пункту "Сертификаты", там есть кнопка с названием "Просмотр сертификатов...", кликните на неё.

Откроется окно работы с сертификатами:

Шаг 1 из 3.
Шаг 1 из 3.

Выберите вкладку "Центры сертификации" и нажмите на кнопку "Импортировать", откроется следующее окно:

Шаг 2 из 3.
Шаг 2 из 3.

Поставьте галочку "Доверять при идентификации веб-сайтов" и нажмите "Ок".

Шаг 3 из 3.
Шаг 3 из 3.

Наш центр сертификации добавился в список к сотням других центров сертификации.

Обратите внимание, среди всех, как ни странно, нет ни одного Российского!
Может быть стоит об этом задуматься? Это точно не просто так.

Андроид

Увы, у меня нет ничего на андроиде, но я думаю что добавление своего центра сертификации на андроид мало отличимо от описанного выше добавления в linux или iOS, особенно учитывая что Android это модифицированный linux. Думаю, что когда у меня появится что-либо на Android я дополню эту инструкцию шагами и скриншотами с тем что необходимо сделать. А пока, можете посмотреть инструкцию на Госуслугах по добавлению Российских центров сертификации на Андроид, ссылка есть выше.

Серверная часть или приложение

Теперь перейдём к той части, где я покажу как работать с нашим самоподписанным сертификатом на серверной стороне.

Если вы бэк-энд разработчик, то вам не составит труда написать сервер и добавить код загрузки сертификата, но если вы не back-end разработчик, то смотреть на не понятный код не стоит, и вы всё равно будете использовать скорее всего обратный прокси для "терминации" TLS на сервере, а в своё приложение направите не шифрованный трафик, вот об этом я и расскажу в этой главе.

В качестве обратного прокси возьмём nginx.

В качестве среды выполнения будет использоваться docker контейнер, для того чтобы вы могли всё это повторить на macOS, linux или windows без каких-либо изменений, всё показанное ниже идентично работает на любой ОС, потому что используется docker.

Итак, нам потребуется:

  1. Минимальный конфигурационный файл для nginx;
  2. Файл для сборки Docker образа;
  3. Наш сертификат, подписанный нашим центром сертификации;

Открываем свой любимый текстовый редактор и создаём файл с названием nginx.conf. Вписываем в него следующее содержимое:

worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
large_client_header_buffers 4 32k;
server {
listen 80;
server_name backend;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name backend;
ssl_certificate /etc/ssl/certs/localhost.crt;
ssl_certificate_key /etc/ssl/private/localhost.key;
ssl_trusted_certificate /etc/ssl/certs/localhost_full.crt;
location / {
root /usr/share/nginx/html;
autoindex on;
}
}
}

Создаём файл localhost_full.crt путём конкатенации двух сертификатов, сертификата нашего центра сертификации root_ca.crt и сертификата localhost.crt, это можно сделать в любом текстовом редакторе, либо выполнив команду:

cat root_ca.crt localhost.crt > localhost_full.crt

Создаём файл сборки докер образа, он должен называться Dockerfile и вписываем в него следующее содержимое:

FROM nginx@latest
COPY nginx.conf /etc/nginx/nginx.conf
COPY localhost.crt /etc/ssl/certs/localhost.crt
COPY localhost.key /etc/ssl/private/localhost.key
COPY localhost_full.crt /etc/ssl/certs/localhost_full.crt
CMD ["nginx", "-g", "daemon off;"]

Все конфигурации готовы, можем запускать.

docker build -t tls-nginx .

Этой командой мы создаём docker образ и называем его "tls-nginx".
Теперь всё готово к тому чтобы запустить nginx, выполняем команду:

docker run \
-d \
-p 80:80 \
-p 443:443 \
-v ./:/usr/share/nginx/html:ro \
tls-nginx

Поясню что мы сделали, по каждому параметру отдельно:

  • run - Команда докера, запускает на выполнение контейнер;
  • -d - Параметр указывает то что контейнер должен запустится в фоновом режиме и вернуть управление;
  • -p - Параметр указывает какие порты локального компьютера должны быть проброшены внутрь контейнера. В нашем случае были проброшены порты 80 и 443 локального компьютера в докер контейнер на порты 80 и 443 соответственно. Вы можете указать другие порты локального компьютера;
  • -v - Параметр указывает какая директория локального компьютера монтируется в директорию докер контейнера. ./ - это текущая директория на локальном компьютере. Директория /usr/share/nginx/html ранее в конфигурационном файле nginx была указана как директория root для отображения файлов;
  • tls-nginx - В этом параметре указываем докеру какой образ ему необходимо запустить. Ранее, мы создали образ с этим именем.

Чтобы не вводить эту длинную команду каждый раз, я запишу её в файл run.sh, те кто использует Windows могут создать аналогичный файл, у них он будет называться например run.cmd.
Пример содержимого файла
run.sh:

#!/bin/bash
docker run \
-d \
-p 80:80 \
-p 443:443 \
-v ./:/usr/share/nginx/html:ro \
tls-nginx

Теперь мы можем открыть браузер и перейти по адресу https://localhost/ и мы увидим то, чего добивались, наша страница откроется без сообщений об угрозах, на самоподписанном сертификате, в стандартном браузере и через nginx сервер, запущенный локально.

Результат - браузер Safari.
Результат - браузер Safari.
Результат - браузер Chrome.
Результат - браузер Chrome.
Результат - браузер Yandex.Браузер.
Результат - браузер Yandex.Браузер.
Результат - браузер firefox.
Результат - браузер firefox.

Успехов!