Как мне создать HashCode в .net (c #) для строки, которую безопасно хранить в базе данных? - PullRequest
43 голосов
/ 01 марта 2011

Цитировать из Руководства и правила для GetHashCode Эрика Липперта:

Правило: Потребители GetHashCode не могут полагаться на то, что он стабилен во времени или во всех доменах приложений

Предположим, у вас есть объект Customer, имеющий несколько полей, таких как Имя, Адрес и т. Д.Если вы создадите два таких объекта с одинаковыми данными в двух разных процессах, им не нужно возвращать один и тот же хэш-код.Если вы создадите такой объект во вторник в одном процессе, закроете его и снова запустите программу в среду, хэш-коды могут отличаться.

Это укусило людей в прошлом.В документации для System.String.GetHashCode особо отмечается, что две идентичные строки могут иметь разные хеш-коды в разных версиях CLR, и фактически они это делают. Не храните строковые хеши в базах данных и не ожидайте, что они будут такими же навсегда, потому что они не будут такими.

Так что же является правильным способом создания HashCodeстрока, которую я могу хранить в базе данных?

(Скажите, пожалуйста, я не первый, кто оставил эту ошибку в программном обеспечении, которое я написал!)

Ответы [ 3 ]

69 голосов
/ 01 марта 2011

Зависит от того, какие свойства вы хотите, чтобы хеш имел.Например, вы могли бы просто написать что-то вроде этого:

public int HashString(string text)
{
    // TODO: Determine nullity policy.

    unchecked
    {
        int hash = 23;
        foreach (char c in text)
        {
            hash = hash * 31 + c;
        }
        return hash;
    }
}

До тех пор, пока вы документ , то есть то, как вычисляется хэш, это действительно.Это ни в коем случае не криптографически безопасно или что-то в этом роде, но вы можете сохранить его без проблем.Две строки, которые абсолютно равны в обычном смысле (т.е. без применения культурного равенства и т. Д., В точности одинаковые символы), будут создавать одинаковый хэш с этим кодом.

Проблемы возникают, когда вы полагаетесь на недокументированное хеширование - то есть то, что подчиняется GetHashCode(), но ни в коем случае не гарантируется, что оно останется неизменным от версии к версии ... как string.GetHashCode().

Запись и документирование вашего собственного хэшакак это немного похоже на высказывание: «Эта конфиденциальная информация хешируется с помощью MD5 (или чего-либо еще)».Пока это хорошо определенный хеш, это нормально.

РЕДАКТИРОВАТЬ: Другие ответы предлагали использовать криптографические хеши, такие как SHA-1 или MD5.Я бы сказал, что пока мы не узнаем, что существует требование криптографической безопасности, а не просто стабильности, нет смысла проходить через сложную задачу преобразования строки в байтовый массив и хэширования.Конечно, если хеш равен , предназначенным для использования с чем-либо, связанным с безопасностью, то отраслевой стандарт хеша равен точно , чего вы должны достичь.Но это нигде не упоминалось в этом вопросе.

7 голосов
/ 25 апреля 2016

Вот переопределение текущего способа .NET вычисляет свой строковый хэш-код для 64-битных систем .Он не использует указатели, как настоящие GetHashCode(), поэтому он будет немного медленнее, но он делает его более устойчивым к внутренним изменениям string, это даст более равномерно распределенный хэш-код, чем версия Джона Скита, что может улучшить время поиска в словарях.

public static class StringExtensionMethods
{
    public static int GetStableHashCode(this string str)
    {
        unchecked
        {
            int hash1 = 5381;
            int hash2 = hash1;

            for(int i = 0; i < str.Length && str[i] != '\0'; i += 2)
            {
                hash1 = ((hash1 << 5) + hash1) ^ str[i];
                if (i == str.Length - 1 || str[i+1] == '\0')
                    break;
                hash2 = ((hash2 << 5) + hash2) ^ str[i+1];
            }

            return hash1 + (hash2*1566083941);
        }
    }
}
2 голосов
/ 01 марта 2011

Ответ - написать свою собственную функцию хеширования. Вы можете найти источник для некоторых, перейдя по ссылкам в комментариях к статье, которую вы опубликовали. Или вы можете использовать встроенную хэш-функцию, которая изначально предназначена для криптографии (MD5, SHA1 и т. Д.), И просто не использовать все биты.

...