← Назад к вопросам

Что такое двуфакторная аутентификации?

1.8 Middle🔥 91 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Двуфакторная аутентификация (2FA): Двойная защита доступа

Двуфакторная аутентификация (2FA) — это механизм безопасности, при котором пользователь должен подтвердить свою личность двумя независимыми способами перед получением доступа к аккаунту. Это значительно повышает безопасность, так как даже если злоумышленник узнает пароль, он не сможет войти без второго фактора.

Три категории аутентификации

2FA использует два из трёх факторов:

1. Знание (Knowledge)
   - То, что только вы знаете
   - Пароль, PIN, секретный вопрос
   
2. Обладание (Possession)
   - То, что только у вас есть
   - Смартфон, аппаратный ключ (YubiKey)
   - Физическая SIM-карта
   
3. Свойство (Inherence)
   - То, что только вы есть
   - Отпечаток пальца
   - Распознавание лица
   - Сетчатка глаза

2FA = Пароль (Знание) + Второй фактор (Обладание или Свойство)

Примеры:
- Пароль + SMS код → 2FA ✓
- Пароль + TOTP (Time-based OTP) → 2FA ✓
- Пароль + Отпечаток пальца → 2FA ✓
- Пароль + Аппаратный ключ → 2FA ✓

Не 2FA:
- Только пароль → 1FA
- Пароль + секретный вопрос → 1FA (оба из категории "Знание")

Методы 2FA

1. SMS 2FA (наиболее распространённая)

Шаги:
1. Пользователь вводит логин и пароль
2. Сервер проверяет данные
3. Сервер отправляет 6-значный код на номер телефона
4. Пользователь вводит код из SMS
5. Доступ предоставлен

Проблемы:
- SMS может быть перехвачена (SIM swap атаки)
- Медленнее, чем другие методы
- Требует интернета у сервера, телефона у пользователя

2. TOTP (Time-based One-Time Password)

Самый популярный метод для 2FA.

Схема:
1. При регистрации сервер генерирует SECRET (например: JBSWY3DPEBLW64TMMQ======)
2. Пользователь сканирует QR-код в приложение (Google Authenticator, Authy)
3. Приложение хранит SECRET локально
4. Каждые 30 секунд приложение генерирует 6-значный код
5. При входе пользователь вводит текущий код
6. Сервер вычисляет ожидаемый код и проверяет

Математика:
TOTP = HOAC(SECRET, time_in_30_second_intervals)
Код меняется каждые 30 секунд, поэтому угадать невозможно

Пример реализации TOTP на Python:

import pyotp
import qrcode
from io import BytesIO

# 1. Генерирование SECRET при регистрации
def generate_totp_secret():
    # Создает случайный SECRET
    secret = pyotp.random_base32()  # Например: "JBSWY3DPEBLW64TMMQ======"
    return secret

# 2. Создание QR кода для пользователя
def get_totp_qr_code(secret: str, username: str, issuer: str = "MyApp"):
    # Создает объект TOTP
    totp = pyotp.TOTP(secret)
    
    # Генерирует URI для QR кода
    uri = totp.provisioning_uri(
        name=username,
        issuer_name=issuer
    )
    # otpauth://totp/MyApp:user@example.com?secret=JBSWY3DPEBLW64TMMQ======&issuer=MyApp
    
    # Создает QR код
    qr = qrcode.QRCode()
    qr.add_data(uri)
    qr.make()
    
    img = qr.make_image()
    # Возвращаем изображение (отправляем пользователю)
    return img, secret

# 3. Проверка кода при входе
def verify_totp(secret: str, token: str) -> bool:
    totp = pyotp.TOTP(secret)
    
    # Проверяет текущий код
    # По умолчанию ±1 интервал для синхронизации часов
    return totp.verify(token)  # True если правильно

# Использование:
print("=== Регистрация ===")
secret = generate_totp_secret()
print(f"Secret: {secret}")

# Пользователь сканирует QR код
print(f"\n=== Проверка кода при входе ===")

# Пользователь открывает Authenticator и видит 123456
totp = pyotp.TOTP(secret)
token = totp.now()  # Например: "123456"
print(f"Код из Authenticator: {token}")
print(f"Верен ли код? {verify_totp(secret, token)}")

# Через 30 секунд код изменится
token_wrong = "654321"
print(f"Неправильный код: {verify_totp(secret, token_wrong)}")

3. Аппаратные ключи (FIDO2/U2F)

Максимально безопасный способ.

Примеры: YubiKey, Google Titan

Шаги:
1. Пользователь подключает ключ (USB/NFC)
2. При входе сервер отправляет challenge
3. Ключ использует приватный ключ для подписания challenge
4. Сервер проверяет подпись публичным ключом
5. Доступ предоставлен

Преимущества:
- Невозможно фишинг (ключ знает реальный сервер)
- Не требует интернета на устройстве
- Криптографически безопасно

4. Push-уведомления

Мобильное приложение отправляет уведомление:
1. Пользователь вводит пароль
2. Сервер отправляет push на приложение
3. Пользователь видит запрос "Вы пытались войти?"
4. Пользователь нажимает "Подтвердить"
5. Доступ предоставлен

Примеры: Microsoft Authenticator, Duo Push

5. Отпечаток пальца / Лицо (Биометрия)

Модерный способ на смартфонах.

Шаги:
1. Пользователь вводит пароль
2. Смартфон запрашивает отпечаток пальца
3. Если совпал → отправляется подтверждение
4. Доступ предоставлен

Полный пример: 2FA с TOTP на Django/FastAPI

# fastapi_2fa_example.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import pyotp
from sqlalchemy import Column, String, Boolean
from sqlalchemy.ext.declarative import declarative_base

app = FastAPI()
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    
    username: str = Column(String, primary_key=True)
    password_hash: str = Column(String)
    totp_secret: str = Column(String, nullable=True)  # Храним SECRET
    totp_enabled: bool = Column(Boolean, default=False)

class LoginRequest(BaseModel):
    username: str
    password: str

class TOTPVerifyRequest(BaseModel):
    username: str
    token: str

class EnableTOTPResponse(BaseModel):
    secret: str
    qr_code_uri: str

@app.post("/auth/login")
def login(request: LoginRequest, db):
    """
    Шаг 1: Проверка пароля
    """
    user = db.query(User).filter(User.username == request.username).first()
    
    if not user or not verify_password(request.password, user.password_hash):
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    if not user.totp_enabled:
        # 2FA не включена, выдаём токен сразу
        return {"access_token": create_access_token(user.username)}
    
    # 2FA включена, требуем второй фактор
    return {"requires_2fa": True, "username": request.username}

@app.post("/auth/verify-2fa")
def verify_2fa(request: TOTPVerifyRequest, db):
    """
    Шаг 2: Проверка кода TOTP
    """
    user = db.query(User).filter(User.username == request.username).first()
    
    if not user or not user.totp_secret:
        raise HTTPException(status_code=401, detail="2FA not configured")
    
    totp = pyotp.TOTP(user.totp_secret)
    
    if not totp.verify(request.token):
        raise HTTPException(status_code=401, detail="Invalid 2FA code")
    
    # Код верен, выдаём токен
    return {"access_token": create_access_token(user.username)}

@app.post("/settings/enable-2fa")
def enable_2fa(username: str, db):
    """
    Включение 2FA для пользователя
    """
    user = db.query(User).filter(User.username == username).first()
    
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    # Генерируем SECRET
    secret = pyotp.random_base32()
    totp = pyotp.TOTP(secret)
    
    # Генерируем URI для QR кода
    uri = totp.provisioning_uri(
        name=username,
        issuer_name="MyApp"
    )
    
    return {
        "secret": secret,
        "qr_code_uri": uri,
        "message": "Отсканируйте QR код в Google Authenticator, затем подтвердите"
    }

@app.post("/settings/confirm-2fa")
def confirm_2fa(username: str, secret: str, token: str, db):
    """
    Подтверждение 2FA (пользователь ввел код из Authenticator)
    """
    user = db.query(User).filter(User.username == username).first()
    totp = pyotp.TOTP(secret)
    
    if not totp.verify(token):
        raise HTTPException(status_code=400, detail="Invalid token")
    
    # Сохраняем SECRET и включаем 2FA
    user.totp_secret = secret
    user.totp_enabled = True
    db.commit()
    
    return {"message": "2FA enabled successfully"}

@app.post("/settings/disable-2fa")
def disable_2fa(username: str, password: str, db):
    """
    Отключение 2FA (требует пароль для безопасности)
    """
    user = db.query(User).filter(User.username == username).first()
    
    if not verify_password(password, user.password_hash):
        raise HTTPException(status_code=401, detail="Invalid password")
    
    user.totp_enabled = False
    user.totp_secret = None
    db.commit()
    
    return {"message": "2FA disabled"}

Лучшие практики для 2FA

# 1. Резервные коды (Recovery codes)
# На случай если пользователь потеряет доступ к Authenticator
RecoveryCode(
    user_id=user.id,
    code="ABC-DEF-GHI",  # Одноразовый
    used=False
)

# 2. Логирование попыток
LoginAttempt(
    user_id=user.id,
    timestamp=datetime.now(),
    method="totp",
    success=True,
    ip_address="192.168.1.1"
)

# 3. Уведомления о новых девайсах
# Если пользователь входит с нового устройства
if is_new_device(user_id, ip_address):
    send_email(
        user.email,
        "Вход с нового устройства",
        f"Если это не вы, измените пароль"
    )

# 4. Rate limiting на проверку кодов
# Максимум 3 неправильных попытки в минуту
if failed_attempts_last_minute > 3:
    raise HTTPException(status_code=429, detail="Too many attempts")

# 5. Trusted devices
# Запомнить текущее устройство на 30 дней
TrustedDevice(
    user_id=user.id,
    device_id=hash(user_agent + ip_address),
    expires_at=datetime.now() + timedelta(days=30)
)

Сравнение методов 2FA

Метод           Безопасность  Удобство  Стоимость  Когда использовать
────────────────────────────────────────────────────────────────────
SMS             Средняя       Высокая   Низкая     Стартапы, массовые пользователи
TOTP            Высокая       Средняя   0          Привычная, бесплатная
Пуш-notify      Высокая       Высокая   Средняя    Мобильные приложения
Аппаратный ключ Макс          Низкая    Высокая    Корпоративные, пользователи VIP
Биометрия       Высокая       Высокая   0          Смартфоны, ноутбуки

Резюме

2FA — это двойная аутентификация: пароль + второй фактор (SMS, TOTP, ключ, биометрия). Это значительно повышает безопасность. Самые популярные методы: TOTP (Google Authenticator) и SMS. При внедрении 2FA важны резервные коды, логирование, rate limiting и доверенные устройства для баланса между безопасностью и удобством.