Thousands of people around the world make our work possible. Donate today.

Сертифікати для локального хоста

Останнє оновлення: | Переглянути всю документацію

Іноді розробникам потрібен сертифікат для доменного імені “localhost” — для локальної розробки, або для поширення всередині нативних застосунків для взаємодії з вебзастосунком. Let’s Encrypt не може надавати сертифікати для “localhost”, тому що по-перше, у цього доменного імені немає певного власника, і по-друге, немає домену першого рівня — наприклад, “.com” або “.net”. Можна налаштувати доменне ім’я так, щоб воно переходило на адресу 127.0.0.1, і випустити для нього сертифікат після проходження перевірки DNS. Проте, є більш вдалі рішення.

Для локальної розробки

При розробці вебзастосунку зазвичай запускають локальний вебсервер, наприклад, Apache або Nginx, та отримати доступ до нього через http://localhost:8000/ у браузері. Проте, браузери по-різному обробляють HTTP та HTTPS запити. Головна відмінність — це те, що на HTTPS-сторінці будь-яка спроба завантажити Javascript за HTTP-протоколом буде заблокована. Тому, при локальній розробці з використанням HTTP скрипти будуть завантажуватися нормально, але після викладення на робочі HTTPS-сервера виникнуть проблеми. Для уникнення проблеми необхідно налаштувати HTTPS на локальному сервері. Однак, вам непотрібні постійні повідомлення про помилку сертифіката. Як побачити “зелений замок” в адресному рядку?

Найкращим рішенням буде створення власного сертифіката, підписаний вами або локальним кореневим сертифікатом, який ви маєте додати до сховища довіри своєї оперативної системи. Використовуйте цей сертифікат у вашому локальному вебсервері. Деталі див. нижче.

Для нативних додатків, які взаємодіють із вебдодатками

Інколи розробники пропонують нативний додаток, який можна використовувати водночас із вебсайтом для додаткових функцій. Наприклад, десктоп-застосунки Dropbox і Spotify сканують файли на дисках комп’ютера, що неможливо для вебзастосунків. Загальний підхід в реалізації таких нативних додатків полягає в запуску вебслужби на локальному хості і обміну даними з вебзастосунком через XMLHTTPRequest (XHR) або WebSockets. Вебзастосунки, як правило, використовують HTTPS, тому XHR- або WebSockets-запити за незахищеним URL будуть відхилені. Це називається “блокування змішаного контенту”. Для взаємодії з вебзастосунками, нативний застосунок має бути безпечним.

На щастя, сучасні браузери вважають http://127.0.0.1:8000/ “потенційно надійною” URL-адресою, тому що це адреса “внутрішньої петлі” (loopback). Відправлений на 127.0.0.1 трафік гарантовано не покине ваш комп’ютер, тому вважається безпечним у разі перехоплення мережевого трафіку. Тобто, якщо вебзастосунок використовує HTTPS, а нативний застосунок запущений на 127.0.0.1, то обидві програми можуть успішно взаємодіяти з XHR. На даль, для localhost це ще так не працює. Із WebSockets та ж сама ситуація.

Можливо, ви захочете обійти ці обмеження, налаштовуючи резолв доменного імені в глобальному DNS 127.0.0.1 (наприклад, localhost.example.com), видавши сертифікат на це доменне ім’я, розповсюджуючи сертифікат та відповідний йому закритий ключ всередині нативного застосунку та налаштувавши взаємодію по https://localhost.example.com:8000/ замість http://127.0.0.1:8000/. Не робіть цього. Ваші користувачі наражаться на ризик, а ваш сертифікат може буде відкликано.

Використовуючи доменне ім’я замість IP-адреси, ви дозволяєте зловмисникам запустити атаку Man in the Middle (MitM) в процесі пошуку IP-адреси по доменному імені DNS Lookup, і впровадити відповідь, яка вкаже на іншу IP-адресу. Зловмисник може вдати з себе нативний застосунок, підробляючи запити до вебзастосунку, що скомпрометує аккаунт з боку застосунка залежно від того, як він розроблений.

Успішний MitM в цій ситуації можливий тому, що для того, щоб змусити його працювати, вам потрібно було відправити приватний ключ до вашого сертифікату разом з вашим рідним додатком. Це означає, що будь-хто, хто завантажить ваш нативний додаток, отримає копію приватного ключа, включаючи зловмисника. Цим ви скомпрометуєте закритий ключ, і Центр сертифікації (ЦС) відкличе сертифікат, як тільки дізнається про це. У багатьох нативних застосунків сертифікати були відкликані через поширення закритого ключа.

На жаль, це звужує список безпечних способів взаємодії нативних і вебзастосунків. І ситуація може ще більше ускладнитися в недалекому майбутньому, якщо браузери продовжать ускладнювати доступ до локального хоста.

Також зверніть увагу, що експорт веб-сервісу з доступом до нативного API є ризикованим, тому що сайти, які ви не мали наміру авторизувати, можуть отримати доступ до цього API. Якщо вирішите заглибитися у вивчення проблеми, зверніть увагу на Cross-Origin Resource Sharing, використайте Access-Control-Allow-Origin, а також надійного HTTP-аналізатора. Навіть сервери, що не пройшли доступ, можуть надсилати попередні запити та експлуатути уразливості в HTTP-аналізаторі.

Створення та перевірка власних сертифікатів

Будь-хто може створити свій сертифікат без ЦС. Єдина відмінність в тому, що випущені вами сертифікати більше ніким не будуть прийматися. Для локальної розробки цього достатньо.

Найпростіший спосіб згенерувати закритий ключ і самоподпісанний сертифікат для localhost - виконати наступну команду з пакета openssl:

openssl req -x509 -out localhost.crt -keyout localhost.key \
  -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=localhost' -extensions EXT -config <( \
   printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

Ви можете налаштувати локальний вебсервер, використовуючи файли localhost.crt і localhost.key, додавши localhost.crt в список довірених кореневих сертифікатів.

Якщо вам потрібно трохи більше реалізму в сертифікатах для локальної розробки, спробуйте minica для створення локального кореневого сертифікату і випуску кінцевого сертифікату (кінцевого вузла), підписаного ним. У підсумку ви будете імпортувати кореневий сертифікат замість самопідписаного кінцевого сертифікату.

Ви також можете використовувати доменне ім’я з крапаками всередині, наприклад www.localhost, додаючи /etc/hosts як псевдонім до 127.0.0.1. Цей підхід трохи змінить спосіб обробки браузерами сховища для cookie.