|
1 | 1 | --- |
| 2 | +title: Сертификаты для localhost |
2 | 3 | slug: certificates-for-localhost |
3 | | -untranslated: 1 |
| 4 | +top_graphic: 1 |
| 5 | +date: 2017-12-21 |
| 6 | +lastmod: 2017-12-21 |
4 | 7 | --- |
| 8 | + |
| 9 | +{{< lastmod >}} |
| 10 | + |
| 11 | +Иногда разработчикам нужен сертификат для доменного имени "localhost" - для локальной разработки, или для распространения внутри нативных приложений для взаимодействия с web-приложением. Let's Encrypt не предоставляет сертификатов для "localhost", т.к. во-первых, у этого доменного имени нет определённого владельца, и во-вторых, нет домена первого уровня - например, ".com" или ".net". Теоретически, возможно настроить доменное имя так, чтобы оно резолвилось на адрес `127.0.0.1`, и выпустить для него сертификат после прохождения проверки DNS. Тем не менее, есть более удачные решения. |
| 12 | + |
| 13 | +# Для локальной разработки |
| 14 | + |
| 15 | +При разработке web-приложения обычно запускают локальный web-сервер (Apache, Nginx), настроенный на `http://localhost:8000/`. Однако, браузеры по-разному обрабатывают HTTP- и HTTPS-запросы. На HTTPS-странице попытка загрузить Javascript по HTTP-протоколу будет заблокирована. Поэтому, при локальной разработке, используя HTTP, скрипты будут загружаться нормально, но после выкладки на боевые HTTPS-сервера возникнут проблемы. Чтобы избежать такой ситуации, нужно настроить доступ по HTTPS на локальном web-сервере. Но как избавиться от постоянных сообщений об ошибке сертификата, как увидеть "зелёный зам**о**к" в адресной строке? |
| 16 | + |
| 17 | +Лучшим решением будет создание собственного сертификата - самоподписанного, или подписанного локальным корневым сертификатом - и добавление в доверенное хранилище операционной системы. Подробности см.ниже. |
| 18 | + |
| 19 | +# Для нативных приложений, взаимодействующих с web-приложениями |
| 20 | + |
| 21 | +Время от времени, разработчики вынуждены выпускать загружаемые нативные приложения, для расширения функциональности и совместного использования с web-приложениями. Например, десктоп-приложения Dropbox и Spotify умеют сканировать файлы на дисках компьютера, что невозможно для web-приложений. Общий подход в реализации таких нативных приложений состоит в запуске локального web-сервера, и обмену данными с web-приложением через XMLHTTPRequest (XHR) или WebSockets. Web-приложения, как правило, используют HTTPS, поэтому XHR- или WebSockets-запросы по небезопасному протоколу HTTP будут отклонены. Это называется "блокировка смешаного контента" (Mixed Content Blocking). Для взаимодействия с web-приложением, нативное приложение должно быть безопасным. |
| 22 | + |
| 23 | +С одной стороны, современные браузеры [считают][mcb-localhost] `http://127.0.0.1:8000/` ["потенциально заслуживающим доверие"][secure-contexts] URL-ом, потому что он локальный. Отправленный на `127.0.0.1` трафик гарантированно не уйдёт за пределы компьютера, соответственно, считается безопасным для перехвата по сети. Это означает, что если web-приложение использует HTTPS, а нативное приложение запущено на `127.0.0.1`, то обе программы могут успешно взаимодействовать по XHR. |
| 24 | +С другой стороны, [для localhost это ещё не работает][let-localhost]. А WebSocket-ы игнорируют и `127.0.0.1`, и `localhost`. |
| 25 | + |
| 26 | +Возможно, вы захотите обойти эти ограничения, настроив резолв произвольного доменного имени в глобальном DNS на адрес `127.0.0.1` (например, `localhost.example.com`), выпустив сертификат для этого домена, распространяя сертификат и соответствующий ему закрытый ключ внутри нативного приложения, и настроив взаимодействие по `https://localhost.example.com:8000/` вместо `http://127.0.0.1:8000/`. *Не делайте этого!* Это подвергнет пользователей риску, и сертификат может быть отозван. |
| 27 | + |
| 28 | +Используя доменное имя вместо IP-адреса, вы позволяете злоумышленникам запустить атаку Man in the Middle (MitM) в процессе поиска IP-адреса по доменному имени (DNS Lookup), и внедрить ответ, который укажет на другой IP-адрес. Атакующий может притвориться нативным приложением, подделывая запросы к web-приложению, что скомпрометирует аккаунт в web-приложении. |
| 29 | + |
| 30 | +Успех атаки MitM возможен потому, что вы вынуждены распространять закрытый ключ для сертификата вместе с нативным приложением. Соответственно, любой, кто скачает это приложение, получит копию ключа. Этим вы скомпрометируете закрытый ключ, и Удостоверяющий Центр (УЦ) отзовёт сертификат, как только узнает об этом. У [множества нативных приложений][mdsp1] были отозваны [сертификаты][mdsp2] по причине [распространения закрытых ключей][mdsp3]. |
| 31 | + |
| 32 | +К сожалению, это сужает список безопасных способов взаимодействия нативных и web-приложений. И ситуация может ещё больше усложниться в недалёком будущем, если браузеры продолжат [затруднять доступ к localhost][tighten-access]. |
| 33 | + |
| 34 | +Так же нужно отметить, что web-сервисы с доступом к нативному API изначально небезопасны, потому что сайты, которые вы не намеревались авторизовать, могут получить доступ к этому API. Если решите углубиться в изучение проблемы, обратите внимание на [Cross-Origin |
| 35 | +Resource Sharing][cors], использование заголовка ответа Access-Control-Allow-Origin, и надёжного HTTP-парсера. Потому как даже серверы, не прошедшие подтверждение, могут посылать предварительные запросы, эксплуатирующие уязвимости в HTTP-парсере. |
| 36 | + |
| 37 | +# Создание и поверка собственных сертификатов |
| 38 | + |
| 39 | +Любой может выпустить собственный сертификат без обращения к УЦ. Единственное различие будет в том, что выпущенные вами сертификаты не будут приниматься кем-либо ещё. Для локальной разработки этого достаточно. |
| 40 | + |
| 41 | +Простейший способ сгенерировать закрытый ключ и самоподписанный сертификат для localhost - выполнить следующую команду из пакета openssl: |
| 42 | + |
| 43 | + openssl req -x509 -out localhost.crt -keyout localhost.key \ |
| 44 | + -newkey rsa:2048 -nodes -sha256 \ |
| 45 | + -subj '/CN=localhost' -extensions EXT -config <( \ |
| 46 | + printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth") |
| 47 | + |
| 48 | +Вы можете сконфигурировать локальный web-сервер, используя файлы localhost.crt и localhost.key, добавив localhost.crt в список доверенных корневых сертификатов. |
| 49 | + |
| 50 | +Если вам требуется чуть больше реализма в сертификатах для локальной разработки, попробуйте [minica][minica] для создания собственного корневого сертификата, и выпуска конечных сертификатов, подписанных корневым. В итоге вы будете импортировать корневой сертификат вместо самоподписанных конечных сертификатов. |
| 51 | + |
| 52 | +Также, вы можете использовать доменное имя с точками внутри (например, `www.localhost`), добавив в файл /etc/hosts как алиас адреса `127.0.0.1`. Этот подход чуть изменит способ обработки браузерами хранилища для cookie. |
| 53 | + |
| 54 | +[mcb-localhost]: https://bugs.chromium.org/p/chromium/issues/detail?id=607878 |
| 55 | +[secure-contexts]: https://www.w3.org/TR/secure-contexts/#is-origin-trustworthy |
| 56 | +[let-localhost]: https://tools.ietf.org/html/draft-ietf-dnsop-let-localhost-be-localhost-02 |
| 57 | +[mdsp1]: https://groups.google.com/d/msg/mozilla.dev.security.policy/eV89JXcsBC0/wsj5zpbbAQAJ |
| 58 | +[mdsp2]: https://groups.google.com/d/msg/mozilla.dev.security.policy/T6emeoE-lCU/-k-A2dEdAQAJ |
| 59 | +[mdsp3]: https://groups.google.com/d/msg/mozilla.dev.security.policy/pk039T_wPrI/tGnFDFTnCQAJ |
| 60 | +[tighten-access]: https://bugs.chromium.org/p/chromium/issues/detail?id=378566 |
| 61 | +[minica]: https://github.com/jsha/minica |
| 62 | +[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS |
0 commit comments