Какие алгоритмы хеширования вы используете для генерации токенов и паролей?

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

Ответ

Выбор алгоритма зависит от цели: хеширование паролей и создание криптографических подписей для токенов — это разные задачи.

1. Для хеширования паролей (должно быть медленным):

  • PBKDF2 (Password-Based Key Derivation Function 2): Стандартный выбор в .NET. Использует множество итераций хеш-функции (например, SHA-256) вместе с "солью" (salt), что сильно замедляет перебор.
    using System.Security.Cryptography;
    // Генерация хеша
    public byte[] HashPassword(string password, out byte[] salt)
    {
        salt = RandomNumberGenerator.GetBytes(32); // Уникальная соль для каждого пароля
        using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 600000, HashAlgorithmName.SHA256);
        return pbkdf2.GetBytes(32); // 256-битный хеш
    }
    // Верификация
    public bool VerifyPassword(string password, byte[] storedHash, byte[] storedSalt)
    {
        using var pbkdf2 = new Rfc2898DeriveBytes(password, storedSalt, 600000, HashAlgorithmName.SHA256);
        byte[] testHash = pbkdf2.GetBytes(32);
        return CryptographicOperations.FixedTimeEquals(storedHash, testHash); // Сравнение, защищенное от атак по времени
    }
  • BCrypt / Argon2: Считаются более устойчивыми к атакам с использованием специализированного железа (ASIC/GPU). В .NET используются через сторонние библиотеки (например, BCrypt.Net-Next).

2. Для подписи токенов (должно быть быстрым и криптостойким):

  • HMAC-SHA256/512 (Hash-based Message Authentication Code): Основа для подписи JWT (JSON Web Tokens). Гарантирует, что токен не был изменен после выдачи.
    using System.Security.Cryptography;
    // Создание подписи для данных
    public byte[] SignData(byte[] data, byte[] secretKey)
    {
        using var hmac = new HMACSHA256(secretKey); // Секретный ключ известен только серверу
        return hmac.ComputeHash(data);
    }
  • Асимметричная подпись (RSA, ECDSA): Используется, когда нужно, чтобы токен мог проверить любая сторона, имеющая открытый ключ, но подписать — только владелец закрытого ключа (например, в микросервисной архитектуре).

Ключевые принципы:

  • Для паролей всегда используйте соль (уникальную для каждого пользователя) и адаптивные функции (большое число итераций).
  • Секретные ключи для HMAC должны генерироваться криптографически стойким генератором и храниться в защищенном месте (Key Vault).
  • Избегайте устаревших алгоритмов: MD5, SHA1 считаются небезопасными для этих целей.