HTTPS и SSL/TLS
HTTPS — протокол защищённой передачи данных. Использует TLS (Transport Layer Security) для шифрования трафика между браузером и сервером.
Зачем нужно
Без HTTPS данные передаются открытым текстом: логины, пароли, номера карт видны любому, кто перехватит трафик (Wi-Fi в кафе, провайдер, MITM-атака). HTTPS шифрует всё. Кроме того, без HTTPS: нет Service Workers, нет HTTP/2, поисковики понижают в выдаче, браузеры показывают предупреждение «Не защищено».
Где используется
Абсолютно все публичные веб-сайты и API. С 2018 года Chrome помечает HTTP-сайты как небезопасные. Let's Encrypt сделал SSL-сертификаты бесплатными.
Предпосылки
Базовое понимание HTTP, DNS, клиент-серверная архитектура
Как работает TLS Handshake
Клиент (браузер) Сервер
│ │
1. │── ClientHello ──────────────────► │ (версия TLS, cipher suites)
│ │
2. │◄──────────────── ServerHello ──│ │ (выбранный cipher, сертификат)
│ │
3. │ Проверяет сертификат │ (CA, срок, домен)
│ │
4. │── Pre-master secret ────────────► │ (зашифрован публичным ключом)
│ │
5. │◄──── Оба вычисляют session key ──►│ (симметричный ключ)
│ │
6. │════ Шифрованный трафик ═══════════│ (AES-256 и т.д.)
Упрощённо:
- Браузер и сервер договариваются о протоколе шифрования
- Сервер показывает свой сертификат (удостоверение личности)
- Браузер проверяет сертификат через цепочку доверия (CA)
- Обмениваются ключами через асимметричное шифрование
- Дальше общаются через быстрое симметричное шифрование
SSL-сертификаты
Типы сертификатов
| Тип | Проверка | Для кого |
|---|---|---|
| DV (Domain Validation) | Владение доменом | Блоги, личные сайты |
| OV (Organization Validation) | Организация проверена | Бизнес-сайты |
| EV (Extended Validation) | Углублённая проверка | Банки, крупные компании |
Let's Encrypt — бесплатные сертификаты
# Установка certbot
sudo apt install certbot python3-certbot-nginx
# Получение сертификата для nginx
sudo certbot --nginx -d example.com -d www.example.com
# Автообновление (сертификат действует 90 дней)
sudo certbot renew --dry-run
# Cron для автообновления
0 0 1 * * certbot renew --quiet
Настройка Nginx с HTTPS
server {
listen 80;
server_name example.com www.example.com;
# Редирект HTTP → HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Современные настройки TLS
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# HSTS — принудительный HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://localhost:3000;
}
}
HTTPS в Node.js
Express + HTTPS
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express;
// Для production: путь к Let's Encrypt сертификатам
const options = {
key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/example.com/fullchain.pem'),
};
https.createServer(options, app).listen(443, () => {
console.log('HTTPS сервер на порту 443');
});
// Редирект HTTP → HTTPS
const http = require('http');
http.createServer((req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
}).listen(80);
Express за reverse proxy (Nginx/Cloudflare)
// Если HTTPS терминируется на прокси, Express видит HTTP
// Нужно доверять заголовку X-Forwarded-Proto
app.set('trust proxy', 1);
// Middleware для редиректа
app.use((req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(301, `https://${req.hostname}${req.url}`);
}
next;
});
HSTS (HTTP Strict Transport Security)
Заголовок, который говорит браузеру: «Всегда используй HTTPS для этого домена».
// Express
app.use((req, res, next) => {
res.setHeader(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload'
);
next;
});
// Или через Helmet
const helmet = require('helmet');
app.use(helmet.hsts({
maxAge: 31536000, // 1 год
includeSubDomains: true,
preload: true, // Для HSTS Preload List
}));
| Параметр | Значение |
|---|---|
max-age |
Время в секундах (31536000 = 1 год) |
includeSubDomains |
Распространяется на поддомены |
preload |
Включить в предзагруженный список браузеров |
Миграция HTTP → HTTPS
Чек-лист
- Получить SSL-сертификат (Let's Encrypt)
- Настроить web-сервер (Nginx/Apache)
- Редирект HTTP → HTTPS (301)
- Обновить все ссылки на HTTPS (или использовать
//) - Обновить sitemap.xml и robots.txt
- Обновить URL в Google Search Console
- Включить HSTS
- Проверить mixed content
Mixed Content
<!-- ПРОБЛЕМА: HTTPS-страница загружает HTTP-ресурсы -->
<img src="http://cdn.example.com/image.jpg"> <!-- Blocked! -->
<script src="http://cdn.example.com/app.js"></script> <!-- Blocked! -->
<!-- РЕШЕНИЕ: протокол-относительные URL или HTTPS -->
<img src="https://cdn.example.com/image.jpg">
<script src="//cdn.example.com/app.js"></script>
<!-- CSP для блокировки mixed content -->
<meta http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests">
Проверка HTTPS
# Проверить сертификат
openssl s_client -connect example.com:443 -servername example.com
# SSL Labs — подробный анализ
# https://www.ssllabs.com/ssltest/
# Проверка срока действия
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
Частые ошибки
1. Самоподписанные сертификаты в production
Браузер показывает страшное предупреждение.
Пользователи не будут доверять сайту.
Решение: Let's Encrypt — бесплатно и автоматически.
2. Забыли обновить сертификат
# Let's Encrypt сертификаты действуют 90 дней!
# Настрой certbot renew в cron или systemd timer
3. Mixed content
HTTPS-страница подгружает ресурсы по HTTP.
Браузер блокирует или показывает предупреждение.
Решение: все ресурсы через HTTPS.
4. Устаревшие протоколы
# ПЛОХО: TLS 1.0 и 1.1 уязвимы
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ХОРОШО: только TLS 1.2+
ssl_protocols TLSv1.2 TLSv1.3;
Практика
- Получи бесплатный сертификат Let's Encrypt для тестового домена (или localhost через mkcert)
- Настрой Nginx с HTTPS и редиректом с HTTP
- Добавь HSTS-заголовок в Express-приложение
- Проверь свой сайт на SSL Labs и исправь найденные проблемы
- Настрой автообновление сертификата через cron