Генерация случайных строк в C#: от новичка до профи

Онлайн-тренажер Python для начинающих

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

Начать курс

Как я устал гуглить "random alphanumeric string C#" и написал эту статью

Признайся честно: когда тебе в очередной раз понадобилось сгенерировать случайный код активации, временный пароль или уникальный идентификатор для сессии, ты просто скопировал первый ответ из Stack Overflow? Я тоже так делал. Но проблема в том, что генерация случайных буквенно-цифровых строк в C# — это не одна задача, а целый спектр сценариев. И то, что работает для тестового токена, может провалить аудит безопасности в production.

В этой статье мы разберем все популярные подходы к генерации случайных строк в C#. От наивных решений с Random до криптостойких методов, одобренных OWASP. Ты узнаешь, какой способ выбрать для паролей, какой — для URL-коротких ссылок, а какой лучше вообще забыть. Поехали!

1. Самый простой способ: Random + StringBuilder (но есть нюанс)

Когда я только начинал, моим первым решением был вот такой код:

public static string GenerateRandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    var random = new Random();
    var result = new StringBuilder(length);
    
    for (int i = 0; i < length; i++)
    {
        result.Append(chars[random.Next(chars.Length)]);
    }
    
    return result.ToString();
}

Выглядит логично, правда? Берем алфавит, дергаем случайный индекс, собираем строку. Но у этого метода две серьезные проблемы:

  • Небезопасный Random — класс Random не является криптостойким. Если злоумышленник узнает время создания объекта (а это легко), он может предсказать всю последовательность.
  • Проблема с многопоточностью — если два потока одновременно вызовут new Random() с одинаковым seed (а так часто бывает при быстрых последовательных вызовах), они получат одинаковые строки.

Когда использовать: Только для локальных тестов, генерации имен файлов или отладочных данных. Никогда — для паролей, токенов или ключей шифрования.

Улучшенная версия: статический Random

private static readonly Random _random = new Random();

public static string GenerateRandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    var result = new char[length];
    
    lock (_random)
    {
        for (int i = 0; i < length; i++)
        {
            result[i] = chars[_random.Next(chars.Length)];
        }
    }
    
    return new string(result);
}

Мы добавили lock для потокобезопасности и заменили StringBuilder на массив char — это быстрее. Но проблема предсказуемости осталась.

2. Guid.NewGuid(): случайная строка за одну строку кода

Когда я впервые увидел этот трюк, я подумал: "Гениально!"

string randomString = Guid.NewGuid().ToString("N").Substring(0, 8);

Guid генерирует 128-битное значение, которое почти гарантированно уникально. Метод "N" убирает дефисы. Substring обрезает до нужной длины.

Плюсы:

  • Очень короткий код
  • Не нужно заморачиваться с алфавитом
  • Скорость высокая

Минусы:

  • Guid содержит только шестнадцатеричные символы (0-9, a-f) — алфавит всего из 16 символов
  • Не все версии Guid действительно случайны (версия 1 основана на времени и MAC-адресе)
  • Не подходит для криптографии — структура Guid предсказуема

Когда использовать: Для генерации уникальных идентификаторов записей в базе данных или имен временных файлов. Не для паролей.

3. Path.GetRandomFileName(): случайное имя файла

Мало кто знает, но .NET уже имеет встроенный генератор случайных имен файлов:

string randomString = Path.GetRandomFileName().Replace(".", "").Substring(0, 8);

Метод возвращает строку вроде "b3v5k9vz.w2k". Мы убираем точку и обрезаем.

Плюсы: Быстро, встроено в .NET, использует криптостойкий генератор под капотом.

Минусы: Алфавит ограничен (строчные латинские буквы и цифры). Длина фиксированная (11 символов до удаления точки).

4. Криптостойкий генератор: RNGCryptoServiceProvider

Вот здесь мы переходим к серьезным вещам. Если вам нужна криптостойкая случайная строка в C# для паролей, токенов или ключей — используйте этот метод:

using System.Security.Cryptography;

public static string GenerateCryptoRandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_-+=[]{}|;:',.<>?/";
    var randomBytes = new byte[length * 4]; // 4 байта на символ для устранения смещения
    var result = new char[length];
    
    using (var rng = RandomNumberGenerator.Create())
    {
        rng.GetBytes(randomBytes);
    }
    
    for (int i = 0; i < length; i++)
    {
        uint num = BitConverter.ToUInt32(randomBytes, i * 4);
        result[i] = chars[(int)(num % (uint)chars.Length)];
    }
    
    return new string(result);
}

Что здесь происходит:

  • RandomNumberGenerator.Create() — криптостойкий генератор (в .NET 6+ это RNGCryptoServiceProvider, в старых версиях — другой класс)
  • Мы генерируем случайные байты, а не используем предсказуемый seed
  • Берем по 4 байта на символ, чтобы избежать статистического смещения (modulo bias)

Плюсы:

  • Максимальная безопасность — подходит для генерации паролей и токенов
  • Полный контроль над алфавитом (можно добавить спецсимволы)
  • Нет проблем с многопоточностью

Минусы: Немного медленнее, чем Random (но для 10-50 символов разница незаметна).

5. Современный подход: RandomNumberGenerator.GetItems() (.NET 8+)

Если вы используете .NET 8 или новее, у вас есть элегантный встроенный метод:

using System.Security.Cryptography;

public static string GenerateCryptoRandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    return new string(RandomNumberGenerator.GetItems(chars.ToCharArray(), length));
}

Это

Блоги

Рекомендаций по книгам