Как реализовать двухфакторную аутентификацию (2FA) в Go?

Ответ

Двухфакторная аутентификация (2FA) повышает безопасность, требуя второй фактор подтверждения личности помимо пароля. Самый популярный метод — TOTP (Time-Based One-Time Password), который используется в приложениях вроде Google Authenticator.

Для реализации TOTP в Go отлично подходит библиотека github.com/pquerna/otp.

Процесс реализации:

1. Этап настройки (когда пользователь включает 2FA):

  • Генерация секрета: Для пользователя создается уникальный секретный ключ.
  • Сохранение секрета: Секрет в зашифрованном виде сохраняется в базе данных и привязывается к пользователю.
  • Генерация QR-кода: На основе секрета генерируется URL, который преобразуется в QR-код. Пользователь сканирует его своим authenticator-приложением.
import (
    "github.com/pquerna/otp/totp"
)

// 1. Генерация ключа при настройке 2FA
key, err := totp.Generate(totp.GenerateOpts{
    Issuer:      "YourAppName", // Название вашего приложения
    AccountName: "user@example.com", // Email или логин пользователя
})
if err != nil {
    // обработка ошибки
}

// 2. Сохраните key.Secret() в БД для этого пользователя.
// 3. Сгенерируйте QR-код из key.URL() и покажите его пользователю.
// qrCodeImage, err := qrcode.Encode(key.URL(), qrcode.Medium, 256)

2. Этап верификации (при каждом логине):

  • Пользователь вводит пароль и одноразовый код из своего приложения.
  • Сервер получает код, достает из БД секрет для этого пользователя и проверяет валидность кода.
// passcode - код, введенный пользователем
// secret - секрет, загруженный из БД для этого пользователя
valid := totp.Validate(passcode, secret)

if valid {
    // Код верный, пускаем пользователя
} else {
    // Ошибка, код неверный
}

Другие важные аспекты:

  • Резервные коды: При настройке 2FA сгенерируйте 8-10 одноразовых резервных кодов. Пользователь должен сохранить их в надежном месте на случай утери доступа к authenticator-приложению.
  • SMS-коды: Как альтернативу можно использовать отправку кодов по SMS через сервисы вроде Twilio. Этот метод считается менее безопасным из-за риска перехвата SIM-карты (SIM swapping).