Приведи пример решения проблемы безопасной генерации СМС-кода для двухфакторной аутентификации

«Приведи пример решения проблемы безопасной генерации СМС-кода для двухфакторной аутентификации» — вопрос из категории Безопасность, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основная проблема — использование непредсказуемых (некриптографических) генераторов случайных чисел, что делает коды уязвимыми. Решение — использовать криптографически стойкий генератор.

Неправильный подход (уязвимый):

// НЕ ДЕЛАЙТЕ ТАК! Random не является криптографически безопасным.
var rnd = new Random();
string insecureCode = rnd.Next(100000, 999999).ToString(); // Предсказуемо!

Правильное решение на C#:

using System.Security.Cryptography;

public static class SmsCodeGenerator
{
    // Генерация кода заданной длины из цифр
    public static string GenerateSecureCode(int length = 6)
    {
        if (length <= 0) throw new ArgumentException("Длина кода должна быть положительной.", nameof(length));

        const string chars = "0123456789"; // Для SMS обычно только цифры
        var codeChars = new char[length];

        // Используем криптографический генератор случайных чисел (CSPRNG)
        using (var rng = RandomNumberGenerator.Create())
        {
            // Выделяем буфер для случайных байтов.
            // Для выбора из 10 цифр (0-9) достаточно одного байта на символ.
            byte[] randomBytes = new byte[length];
            rng.GetBytes(randomBytes); // Заполняем буфер криптографически стойкими случайными байтами

            for (int i = 0; i < length; i++)
            {
                // Берем случайный байт и получаем индекс в диапазоне [0, chars.Length)
                // Использование операции % может привести к незначительному смещению,
                // но для 6-значного кода и 10 цифр это приемлемо на практике.
                int index = randomBytes[i] % chars.Length;
                codeChars[i] = chars[index];
            }
        }
        return new string(codeChars);
    }
}

// Использование
string smsCode = SmsCodeGenerator.GenerateSecureCode(); // Например, "429831"

Дополнительные меры безопасности для 2FA:

  1. Ограничение попыток: Блокировка после 3-5 неудачных вводов кода.
  2. Время жизни кода: Код должен быть действителен ограниченное время (например, 5-10 минут).
  3. Защита от перебора: Использовать длинные коды (6+ цифр) и криптографический генератор, как показано выше.
  4. Не логировать код: Код никогда не должен попадать в логи приложения.
  5. Использование специализированных сервисов: Для продакшена рассмотрите использование сервисов вроде Twilio, Authy или встроенных провайдеров ASP.NET Core Identity, которые уже реализуют эти практики.