Сгенерируйте короткий код на основе уникальной строки в C#


Я как раз собираюсь запустить бета-версию нового онлайн-сервиса. Подписчикам бета-версии будет отправлен уникальный "код доступа", который позволит им зарегистрироваться на сервисе.

Вместо того, чтобы хранить список кодов доступа, я думал, что просто сгенерирую код на основе их электронной почты, так как это само по себе уникально.

Моей первоначальной мыслью было объединить письмо с уникальной строкой, а затем Base64 закодировать его. Однако я искал коды, которые немного короче, скажем, 5 цифр длинный.

3 3

3 ответа:

Если сам код доступа должен быть уникальным, то будет трудно обеспечить защиту от коллизий. Если вы допускаете случай, когда два пользователя могут случайно использовать один и тот же код доступа, это становится значительно проще.

Использование кодировки base-64 адреса электронной почты, объединенного с известной строкой, как это предлагается, может привести к уязвимости системы безопасности. Если вы используете вывод base64 адреса электронной почты, объединенного с известным словом, пользователь может просто снять код код доступа и вывести алгоритм, используемый для генерации кода.

Один из вариантов-взять хэш SHA-1-HMAC (System.Криптография.HMACSHA1) адреса электронной почты с известным секретным ключом. Выходные данные хэша представляют собой 20-байтовую последовательность. Затем вы можете детерминированно усечь хэш. Например, в следующем, GetCodeForEmail("test@example.org") дает код 'PE2WEG':
// define characters allowed in passcode.  set length so divisible into 256
static char[] ValidChars = {'2','3','4','5','6','7','8','9',
                   'A','B','C','D','E','F','G','H',
                   'J','K','L','M','N','P','Q',
                   'R','S','T','U','V','W','X','Y','Z'}; // len=32

const string hashkey = "password"; //key for HMAC function -- change!
const int codelength = 6; // lenth of passcode

string GetCodeForEmail(string address)
{
    byte[] hash;
    using (HMACSHA1 sha1 = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(hashkey)))
        hash = sha1.ComputeHash(UTF8Encoding.UTF8.GetBytes(address));
    int startpos = hash[hash.Length -1] % (hash.Length - codelength);
    StringBuilder passbuilder = new StringBuilder();
    for (int i = startpos; i < startpos + codelength; i++)
        passbuilder.Append(ValidChars[hash[i] % ValidChars.Length]);
    return passbuilder.ToString();
}

Вы можете создать специальный хэш из их электронной почты, который составляет менее 6 символов, но это не будет действительно делать этот "уникальный", всегда будут столкновения в таком маленьком пространстве. Я бы предпочел использовать более длинный ключ или хранить заранее сгенерированные коды в таблице.

Итак, похоже, что вы хотите создать хэш-функцию специально для электронных писем, как указал @can poyragzoglu. Очень простой может выглядеть примерно так:

(псевдокод) foreach char c в электронной почте: running total += [Большое Простое Число] * [значение Юникода]

Затем выполните запуск всего % Большого 5-значного числа

Как он указал, однако, это не будет уникальным, если у вас не было отличной хэш-функции. Скорее всего, у вас будут столкновения. Не уверен, что это так вопросы.

Что мне кажется проще, если вы уже знаете действительные электронные письма, просто проверьте электронную почту пользователя против вашего списка действительных при регистрации? Зачем вообще возиться с кодом?

Если вам действительно нужен уникальный идентификатор, самый простой способ сделать это, вероятно, просто использовать то, что называется GUID. C# изначально поддерживает это . Вы можете сохранить это в таблице пользователей. Хотя, это было бы слишком долго для пользователя, чтобы когда-либо запомнить/напечатать, это было бы почти конечно, будьте уникальны для каждого, если это то, что вы пытаетесь сделать.