Лучшие практики SSL/TLS
Рекомендации по настройке безопасных SSL/TLS соединений.
Генерация DH параметров
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Конфигурация Nginx для SSL
Базовая SSL конфигурация
# SSL Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL Session
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# DH Parameters
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
Полная SSL конфигурация сайта
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL Certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL Configuration
include /etc/nginx/snippets/ssl-params.conf;
# Root directory
root /var/www/html;
index index.php index.html index.htm;
# Security headers
include /etc/nginx/snippets/security-headers.conf;
# PHP Processing
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
# Security
fastcgi_param HTTPS on;
fastcgi_param SERVER_PORT 443;
fastcgi_param REQUEST_SCHEME https;
}
# Security
location ~ /\. {
deny all;
}
location ~* \.(log|conf|htaccess|htpasswd|ini|sql)$ {
deny all;
}
}
Создание сниппетов Nginx
SSL параметры
Создаем /etc/nginx/snippets/ssl-params.conf
:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
Заголовки безопасности
Создаем /etc/nginx/snippets/security-headers.conf
:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP Header - настроить под ваше приложение
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
Валидация HTTP
Создание сертификата через HTTP валидацию:
sudo certbot certonly --webroot \
-w /var/www/html \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos \
--no-eff-email
Nginx конфигурация для HTTP валидации
server {
listen 80;
server_name example.com www.example.com;
# Acme Challenge
location /.well-known/acme-challenge/ {
root /var/www/html;
try_files $uri =404;
}
# Redirect все остальное на HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
Валидация DNS
Cloudflare DNS API
# Устанавливаем плагин Cloudflare
sudo apt install python3-certbot-dns-cloudflare
# Создаем файл с API ключом
sudo nano /etc/letsencrypt/cloudflare.ini
Содержимое файла:
dns_cloudflare_email = your-email@example.com
dns_cloudflare_api_key = your-global-api-key
Или с токеном:
dns_cloudflare_api_token = your-api-token
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
# Получаем сертификат
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com \
-d *.example.com \
--email admin@example.com \
--agree-tos \
--no-eff-email
Автообновление сертификатов
Проверка автообновления
sudo certbot renew --dry-run
Настройка cron
sudo crontab -e
Добавляем:
0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
Или через systemd timer
Создаем /etc/systemd/system/certbot-renewal.service
:
[Unit]
Description=Certbot Renewal
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet
ExecStartPost=/bin/systemctl reload nginx.service
Создаем /etc/systemd/system/certbot-renewal.timer
:
[Unit]
Description=Timer for Certbot Renewal
Requires=certbot-renewal.service
[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=3600
[Install]
WantedBy=timers.target
sudo systemctl enable certbot-renewal.timer
sudo systemctl start certbot-renewal.timer
sudo systemctl list-timers | grep certbot
Проверка SSL
SSL тест
# Проверка конфигурации
sudo nginx -t
# Проверка SSL
openssl s_client -connect example.com:443 -servername example.com
# Тест SSL Labs (онлайн)
# https://www.ssllabs.com/ssltest/
Скрипт проверки SSL
#!/bin/bash
# ssl-check.sh
DOMAIN=$1
if [ -z "$DOMAIN" ]; then
echo "Usage: $0 domain.com"
exit 1
fi
echo "Checking SSL for $DOMAIN..."
# Проверка срока действия
echo "=== Certificate Expiry ==="
echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | \
openssl x509 -noout -dates
# Проверка цепочки
echo "=== Certificate Chain ==="
echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 -showcerts 2>/dev/null | \
grep -E "subject=|issuer="
# Проверка TLS версий
echo "=== Supported TLS Versions ==="
for version in ssl2 ssl3 tls1 tls1_1 tls1_2 tls1_3; do
result=$(echo | timeout 3 openssl s_client -$version -connect $DOMAIN:443 2>&1)
if echo "$result" | grep -q "Cipher is"; then
echo "$version: SUPPORTED"
else
echo "$version: NOT SUPPORTED"
fi
done
chmod +x ssl-check.sh
./ssl-check.sh example.com