SECURITY — Безопасность
Версия: 2.1.0
Дата: 2026-03-24
Уровни защиты
┌─────────────────────────────────────────┐
│ ПОЛЬЗОВАТЕЛЬ │
├─────────────────────────────────────────┤
│ 1. HTTPS + HSTS │
├─────────────────────────────────────────┤
│ 2. WAF / Rate Limiting │
├─────────────────────────────────────────┤
│ 3. Аутентификация / Авторизация │
├─────────────────────────────────────────┤
│ 4. Валидация данных │
├─────────────────────────────────────────┤
│ 5. База данных (шифрование) │
└─────────────────────────────────────────┘
1. HTTPS/SSL
Требования
| Параметр |
Требование |
| Протокол |
TLS 1.2+ (TLS 1.3 предпочтительно) |
| Сертификат |
Let's Encrypt или платный |
| Срок действия |
Автообновление за 30 дней |
| Редирект |
HTTP → HTTPS (301) |
Nginx конфигурация
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Современные настройки
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
}
HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Обязательные
# Запрет встраивания в iframe
add_header X-Frame-Options "SAMEORIGIN" always;
# Защита от XSS
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions Policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
Content Security Policy (CSP)
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'unsafe-inline' https://mc.yandex.ru https://www.google-analytics.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https: blob:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://mc.yandex.ru https://www.google-analytics.com;
frame-ancestors 'self';
form-action 'self';
base-uri 'self';
" always;
Проверка
# Проверить заголовки
curl -I https://example.com
# Онлайн-проверка
# https://securityheaders.com
# https://observatory.mozilla.org
3. Защита от атак
XSS (Cross-Site Scripting)
// Экранирование вывода
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// Twig (автоматически)
{{ user.name }} {# экранируется #}
{{ user.bio|raw }} {# НЕ экранируется - осторожно! #}
SQL Injection
// Плохо
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];
// Хорошо - prepared statements
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
// Drupal - всегда использовать Database API
$query = \Drupal::database()->select('users', 'u')
->fields('u', ['name'])
->condition('uid', $uid)
->execute();
CSRF (Cross-Site Request Forgery)
// Форма с токеном
<form method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrfToken ?>">
...
</form>
// Проверка токена
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
throw new Exception('CSRF token mismatch');
}
// Drupal - автоматически в Form API
Clickjacking
# Уже в headers выше
add_header X-Frame-Options "SAMEORIGIN" always;
4. Rate Limiting
Nginx
# Определение зоны
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
# Применение
location /api/ {
limit_req zone=api burst=20 nodelay;
}
location /user/login {
limit_req zone=login burst=5;
}
Fail2ban
# /etc/fail2ban/jail.local
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
action = iptables-multiport[name=nginx, port="http,https"]
logpath = /var/log/nginx/error.log
findtime = 600
maxretry = 10
bantime = 3600
Cloudflare
| Правило |
Действие |
| Rate limit API |
100 req/min → Challenge |
| Rate limit login |
5 req/min → Block |
| Bot protection |
Challenge suspicious |
5. Аутентификация
Пароли
| Требование |
Значение |
| Минимальная длина |
8 символов |
| Сложность |
Буквы + цифры |
| Хэширование |
bcrypt (cost 12+) или Argon2 |
| Хранение |
Только хэш, никогда plaintext |
// Хэширование
$hash = password_hash($password, PASSWORD_ARGON2ID);
// Проверка
if (password_verify($password, $hash)) {
// OK
}
Сессии
// Настройки PHP
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Lax');
ini_set('session.use_strict_mode', 1);
// Регенерация ID после логина
session_regenerate_id(true);
2FA (двухфакторная)
| Метод |
Надёжность |
| SMS |
Низкая (SIM swap) |
| Email |
Средняя |
| TOTP (Google Auth) |
Высокая |
| WebAuthn/Passkey |
Очень высокая |
6. Защита данных
Шифрование в базе
// Шифрование чувствительных данных
$encrypted = openssl_encrypt(
$cardNumber,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
// Хранить: $iv . $tag . $encrypted (base64)
PCI DSS (для карт)
| Требование |
Решение |
| Не хранить CVV |
Никогда |
| Не хранить полный PAN |
Только токен от эквайера |
| Шифрование |
AES-256 |
| Логирование |
Маскировать карты |
Рекомендация: Использовать hosted payment page (ЮKassa, Тинькофф) — карты не проходят через ваш сервер.
Персональные данные (152-ФЗ)
| Данные |
Защита |
| Телефон |
Маскировать в логах (+7***45-67) |
| Email |
Маскировать (u***@mail.ru) |
| Адрес |
Шифровать или минимизировать |
| Пароль |
Только хэш |
7. Резервное копирование
Стратегия 3-2-1
- 3 копии данных
- 2 разных носителя
- 1 копия offsite
Расписание
| Тип |
Частота |
Хранение |
| Полный бэкап |
Еженедельно |
4 недели |
| Инкрементальный |
Ежедневно |
7 дней |
| БД (mysqldump) |
Каждые 6 часов |
48 часов |
| Файлы (rsync) |
Ежедневно |
7 дней |
Скрипт бэкапа
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M)
BACKUP_DIR="/backups"
# База данных
mysqldump -u root shop_db | gzip > $BACKUP_DIR/db_$DATE.sql.gz
# Файлы
tar -czf $BACKUP_DIR/files_$DATE.tar.gz /var/www/shop/
# Отправка в S3
aws s3 cp $BACKUP_DIR/db_$DATE.sql.gz s3://backups/
aws s3 cp $BACKUP_DIR/files_$DATE.tar.gz s3://backups/
# Удаление старых (7 дней)
find $BACKUP_DIR -mtime +7 -delete
Проверка восстановления
- [ ] Ежемесячно тестировать восстановление
- [ ] Документировать процедуру
- [ ] RTO (время восстановления): < 4 часов
- [ ] RPO (потеря данных): < 6 часов
8. Логирование и мониторинг
Что логировать
| Событие |
Уровень |
| Успешный вход |
INFO |
| Неудачный вход |
WARNING |
| Смена пароля |
INFO |
| Изменение email |
INFO |
| Заказ создан |
INFO |
| Ошибка оплаты |
ERROR |
| Подозрительная активность |
ALERT |
Формат логов
{
"timestamp": "2025-12-21T12:00:00Z",
"level": "WARNING",
"event": "login_failed",
"user_id": null,
"ip": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"details": {
"email": "u***@mail.ru",
"reason": "invalid_password",
"attempt": 3
}
}
Алерты
| Событие |
Действие |
| 5 неудачных входов |
Email администратору |
| 10 неудачных входов |
Блокировка IP на 1 час |
| Массовые 4xx/5xx |
SMS/Telegram |
| Падение сервера |
Звонок |
9. DDoS защита
Базовая (Nginx)
# Ограничение соединений
limit_conn_zone $binary_remote_addr zone=conn:10m;
limit_conn conn 20;
# Ограничение запросов
limit_req_zone $binary_remote_addr zone=req:10m rate=5r/s;
limit_req zone=req burst=10 nodelay;
# Таймауты
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 15s;
send_timeout 10s;
Cloudflare
| Режим |
Когда включать |
| Under Attack |
Активная атака |
| I'm Under Attack Mode |
Серьёзная атака |
| Rate Limiting |
Постоянно |
| Bot Fight Mode |
Постоянно |
Защита форм
<!-- Honeypot -->
<input type="text" name="website" style="display:none" tabindex="-1">
<!-- Проверка на сервере -->
if (!empty($_POST['website'])) {
// Бот
exit;
}
10. Обновления
Регулярные обновления
| Компонент |
Частота |
| ОС (security) |
Еженедельно |
| CMS (Drupal) |
При выходе security release |
| PHP |
При выходе security release |
| Nginx |
При выходе security release |
| Зависимости (npm, composer) |
Ежемесячно |
Автоматизация
# Ubuntu - автообновления безопасности
apt install unattended-upgrades
dpkg-reconfigure unattended-upgrades
# Composer audit
composer audit
# npm audit
npm audit
npm audit fix
Drupal Security
# Проверка обновлений
drush pm:security
# Обновление
composer update drupal/core --with-dependencies
drush updatedb
drush cache:rebuild
11. Чеклист безопасности
Критично
- [ ] HTTPS везде (SSL/TLS 1.2+)
- [ ] HSTS включён
- [ ] Security headers настроены
- [ ] Пароли хэшируются (bcrypt/Argon2)
- [ ] SQL Injection защита (prepared statements)
- [ ] XSS защита (экранирование)
- [ ] CSRF токены на формах
- [ ] Rate limiting настроен
- [ ] Резервные копии работают
Важно
- [ ] 2FA для админов
- [ ] Логирование безопасности
- [ ] Fail2ban настроен
- [ ] Файрвол настроен (ufw/iptables)
- [ ] SSH по ключам (не паролям)
- [ ] Минимальные права (least privilege)
Рекомендуется
- [ ] WAF (ModSecurity, Cloudflare)
- [ ] IDS/IPS
- [ ] Регулярный аудит безопасности
- [ ] Penetration testing (ежегодно)
- [ ] Bug bounty программа
12. Контакты при инциденте
Подозрение на взлом:
1. Изолировать сервер (отключить от сети)
2. Сохранить логи и состояние
3. Уведомить: security@company.com
4. Не удалять улики
5. Документировать всё
Утечка данных (152-ФЗ):
1. Уведомить Роскомнадзор (72 часа)
2. Уведомить пострадавших
3. Принять меры по устранению
Версия: 2.1.0