Защита от атак, backup-коды, rate limiting, мониторинг, best practices для production.
Внедрение 2FA в production требует больше, чем просто код. Вы изучите атаки на 2FA, backup-стратегии, мониторинг и best practices.
Атака: Злоумышленник перебирает все возможные коды.
Защита: Rate limiting + ограничение попыток.
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@router.post("/otp/verify")
@limiter.limit("5/minute;20/hour") # 5 попыток в минуту
async def verify_otp(request: Request, code: str):
# ...
passАтака: Поддельный сайт запрашивает код 2FA у пользователя.
Защита: FIDO2/WebAuthn (привязка к домену), TOTP устойчивее SMS.
Легитимный сайт: example.com → TOTP код работает
Фишинговый сайт: examp1e.com → TOTP код не работает (TOTP не привязан к домену)
FIDO2: examp1e.com → Ключ не сработает (origin binding)
Атака: Злоумышленник переносит номер на свою SIM.
Защита: Использовать TOTP/FIDO2 для критичных операций, мониторинг смены устройства.
def detect_sim_swap(phone: str, device_fingerprint: str) -> bool:
stored = redis_client.get(f"phone_fingerprint:{phone}")
if stored and stored != device_fingerprint:
log_security_event("SIM_SWAP_SUSPECTED", phone=phone)
return True
redis_client.set(f"phone_fingerprint:{phone}", device_fingerprint)
return FalseАтака: Перехват и повторная отправка валидного кода.
Защита:
# TOTP: используем код только один раз
used_codes = redis_client.smembers(f"used_totp:{user_id}")
if code in used_codes:
raise SecurityException("Replay attack detected")
redis_client.sadd(f"used_totp:{user_id}", code)
redis_client.expire(f"used_totp:{user_id}", 60) # 2 окна TOTPАтака: Перехват трафика между клиентом и сервером.
Защита: HTTPS (TLS 1.3), HSTS, certificate pinning для мобильных приложений.
# FastAPI: принудительный HTTPS
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
app.add_middleware(HTTPSRedirectMiddleware)
# HSTS заголовок
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
return responseГенерация:
import secrets
import string
from typing import List
def generate_backup_codes(count: int = 10, length: int = 8) -> List[str]:
"""Генерирует одноразовые backup-коды."""
alphabet = string.ascii_lowercase + string.digits
codes = []
for _ in range(count):
code = ''.join(secrets.choice(alphabet) for _ in range(length))
codes.append(code)
return codesХранение (хэширование как пароли):
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
class BackupCodesManager:
def __init__(self):
self.hashed_codes = []
def set_codes(self, plain_codes: List[str]):
"""Хэширует и сохраняет коды."""
self.hashed_codes = [pwd_context.hash(code) for code in plain_codes]
def verify_and_consume(self, code: str) -> bool:
"""Проверяет и удаляет использованный код."""
code = code.replace("-", "").replace(" ", "").lower()
for i, hashed in enumerate(self.hashed_codes):
if pwd_context.verify(code, hashed):
self.hashed_codes.pop(i)
return True
return FalseАльтернатива backup-кодам — один ключ для сброса 2FA.
def generate_recovery_key() -> str:
"""Генерирует ключ восстановления (16 байт = 32 hex символа)."""
return secrets.token_hex(16)
# Хранение: хэш как пароль
hashed_recovery = pwd_context.hash(recovery_key)
# Использование: сброс 2FA
def reset_2fa_with_recovery(user_id: int, recovery_key: str):
stored_hash = get_user_recovery_hash(user_id)
if pwd_context.verify(recovery_key, stored_hash):
disable_2fa(user_id)
generate_new_recovery_key(user_id)
return True
return False| Метрика | Порог алерта | Почему важно |
|---|---|---|
| Failed 2FA rate | > 10% от всех попыток | Возможная атака или проблемы с провайдером |
| SMS delivery rate | < 90% | Проблемы с SMS-провайдером |
| Email delivery rate | < 95% | Проблемы с deliverability, spam |
| TOTP time drift | > 60 секунд | Проблемы с NTP на сервере |
| Rate limit exceeded | > 100/час с одного IP | Возможная DDoS/brute force |
| Backup code usage | Любое использование | Тревожное событие — пользователь потерял доступ |
# app/routes/admin.py
from fastapi import APIRouter, Depends
from redis import Redis
router = APIRouter()
redis_client = Redis(host='localhost', port=6379, decode_responses=True)
@router.get("/admin/2fa-stats")
async def get_2fa_stats():
"""Статистика 2FA для дашборда."""
return {
"total_users": redis_client.get("stats:total_users"),
"users_with_2fa": redis_client.get("stats:users_with_2fa"),
"2fa_adoption_rate": "{:.1f}%".format(
redis_client.get("stats:users_with_2fa") /
redis_client.get("stats:total_users") * 100
),
"2fa_methods": {
"totp": redis_client.get("stats:2fa:totp"),
"sms": redis_client.get("stats:2fa:sms"),
"email": redis_client.get("stats:2fa:email"),
"webauthn": redis_client.get("stats:2fa:webauthn")
},
"failed_attempts_24h": redis_client.get("stats:failed_24h"),
"sms_delivery_rate_24h": redis_client.get("stats:sms_delivery_24h"),
"blocked_ips": redis_client.zcard("blocked_ips")
}
@router.get("/admin/suspicious-activity")
async def get_suspicious_activity():
"""Подозрительная активность за последние 24 часа."""
events = redis_client.zrevrange("security_events:suspicious", 0, 99, withscores=True)
return [
{"event": json.loads(event), "timestamp": score}
for event, score in events
]# alertmanager.yml
groups:
- name: 2fa_security
interval: 30s
rules:
- alert: HighFailedLogins
expr: rate(failed_logins_total[5m]) > 10
for: 2m
labels:
severity: warning
annotations:
summary: "Высокое количество неудачных входов"
description: "{{ $value }} failed logins per second"
- alert: SMSDeliveryFailure
expr: rate(sms_delivery_failed[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "Проблемы с доставкой SMS"
- alert: PossibleBruteForce
expr: rate(rate_limit_exceeded_total[5m]) > 100
for: 1m
labels:
severity: critical
annotations:
summary: "Возможная brute force атака"
- alert: TOTPTimeDrift
expr: abs(totp_time_drift_seconds) > 60
for: 5m
labels:
severity: warning
annotations:
summary: "Рассинхронизация времени TOTP"| Инцидент | Признаки | Действия |
|---|---|---|
| Утечка TOTP-секретов | Уведомление от security team, news | 1. Принудительный сброс 2FA всех пользователей 2. Уведомление пользователей 3. Генерация новых секретов |
| SIM-swap волна | Множественные жалобы на перехват SMS | 1. Временно отключить SMS для критичных операций 2. Требовать дополнительную верификацию 3. Уведомить затронутых пользователей |
| SMS-провайдер down | Delivery rate < 50% | 1. Переключиться на резервный провайдер 2. Предложить TOTP/FIDO2 3. Увеличить время жизни кодов |
| Brute force атака | Rate limit exceeded > 1000/час | 1. Заблокировать IP-диапазоны 2. Включить CAPTCHA 3. Уведомить security team |
1. DETECT (Обнаружение)
└─ Получено уведомление об утечке БД
2. CONTAIN (Сдерживание) — 0-30 минут
├─ Отключить 2FA для всех пользователей (fallback на backup-коды)
├─ Заблокировать все активные сессии
└─ Переключить базу данных на read-only
3. ERADICATE (Устранение) — 30-60 минут
├─ Сгенерировать новые ключи шифрования
├─ Перешифровать все TOTP-секреты
└─ Обновить приложение с новыми ключами
4. RECOVER (Восстановление) — 1-24 часа
├─ Включить 2FA заново
├─ Потребовать от пользователей перенастроить 2FA
└─ Мониторить подозрительную активность
5. LESSONS LEARNED (Анализ) — 1-7 дней
├─ Post-mortem документ
├─ Обновление security policies
└─ Тренировка для команды
def notify_security_breach(user_id: int, breach_type: str):
"""Уведомляет пользователя об инциденте безопасности."""
user = get_user(user_id)
templates = {
"totp_leak": {
"subject": "Важно: Сброс настроек 2FA",
"body": f"""
Здравствуйте, {user.email}!
Мы обнаружили утечку данных, которая могла затронуть
ваши настройки двухфакторной аутентификации.
В целях безопасности мы сбросили ваши настройки 2FA.
Что делать:
1. Войдите в аккаунт с помощью backup-кодов
2. Перейдите в настройки безопасности
3. Настройте 2FA заново
Приносим извинения за неудобства.
"""
},
"sim_swap_detected": {
"subject": "Подозрительная активность с вашим номером",
"body": f"""
Здравствуйте, {user.email}!
Мы обнаружили, что ваш номер телефона используется
с нового устройства. Это может быть признаком SIM-swap атаки.
Если это не вы:
1. Немедленно свяжитесь с вашим оператором связи
2. Смените пароль от аккаунта
3. Используйте backup-коды для входа
Если это вы — проигнорируйте это сообщение.
"""
}
}
template = templates.get(breach_type)
send_email(user.email, template["subject"], template["body"])| Стандарт | Требование | Для кого |
|---|---|---|
| PCI DSS | 2FA для доступа к данным карт | Финансы, e-commerce |
| SOC 2 | MFA для доступа к системам | SaaS, cloud providers |
| ISO 27001 | MFA для критичных систем | Все организации |
| GDPR | "Appropriate security measures" | Обработка данных EU |
| HIPAA | MFA для доступа к медицинским данным | Healthcare, USA |
PCI DSS 8.3.1:
✅ FIDO2/WebAuthn — соответствует (phishing-resistant)
✅ TOTP — соответствует
⚠️ SMS — соответствует, но не рекомендуется
⚠️ Email — соответствует для некритичных операций
SOC 2 CC6.1:
✅ Все методы 2FA соответствуют
⚠️ Требуется документация и мониторинг
Для compliance аудита подготовьте:
1. Security Policy Document
└─ Описание всех методов 2FA, когда применяются
2. Access Control Policy
└─ Кто имеет доступ, как включается 2FA
3. Incident Response Plan
└─ Playbooks для различных инцидентов
4. Audit Logs
├─ Все successful/failed login attempts
├─ 2FA enable/disable события
├─ Backup code usage
└─ Security alerts
5. Risk Assessment
└─ Оценка рисков для каждого метода 2FA
| Метод | Безопасность | UX | Стоимость | Рекомендация |
|---|---|---|---|---|
| FIDO2/WebAuthn | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | Средняя | Для всех пользователей |
| TOTP | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Бесплатно | Для технических пользователей |
| SMS | ⭐⭐ | ⭐⭐⭐⭐⭐ | $$$ | Как опция, не для критичных |
| ⭐⭐⭐ | ⭐⭐⭐⭐ | Бесплатно | Как резервный метод |
Primary: FIDO2/WebAuthn (если устройство поддерживает)
Secondary: TOTP (Google Authenticator)
Backup: SMS или Email + Backup-коды
┌──────────────────┐
│ CDN / WAF │ ← DDoS защита, rate limiting
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Load Balancer │
└────────┬─────────┘
│
▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ FastAPI App │────▶│ PostgreSQL │ │ Redis │
│ (2FA Logic) │ │ (users, keys) │ │ (sessions, rate) │
└────────┬─────────┘ └──────────────────┘ └──────────────────┘
│
├──────────────────┬──────────────────┬──────────────────┐
▼ ▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Twilio │ │ SendGrid │ │ ELK Stack │ │ Prometheus │
│ (SMS) │ │ (Email) │ │ (Logs) │ │ (Metrics) │
└──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘
Курс завершён! Вы изучили все основные методы 2FA и готовы внедрять их в production.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.