Защита хэшей паролей от обратного проектирования таблиц Rainbow с заполнением пароля

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

Он также поставляется с этим примером кода C#, который в основном требует хранения двух хэш-столбцов в ваших пользовательских паролях. таблица базы данных (вместо традиционной - одна). Проблема такого подхода для меня в том, что у меня уже есть установленная таблица базы данных с несолеными хэшами паролей пользователей, и добавление новой колонки потребует реструктуризации базы данных. Поэтому, прежде чем я это сделаю, я искал другую альтернативу, и вот что я придумал.

Вот функция, которая вместо простого вычисления хэша SHA1 для пароля дополняет его длинной последовательностью псевдослучайных (но непротиворечивых) данных, а затем вычисляет хэш:

byte[] computeSecureHash(string strUserPassword)
{
    //RETURN: = SHA1 byte array on the 'strUserPassword'

    //Make simple junk array based on the password
    ushort v = 117;
    byte[] arrJunk = new byte[24];
    for (int c = 0, i = 0; i < arrJunk.Length; i++)
    {
        v ^= strUserPassword[c++];
        v *= 7;
        arrJunk[i] = (byte)v;

        if (c >= strUserPassword.Length)
            c = 0;
    }

    //Make crypto byte array based on the password
    Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(strUserPassword, arrJunk);
    pbkdf2.IterationCount = 1000;
    byte[] arrCrypto = pbkdf2.GetBytes(128);

    //Pad actual password
    string strUserPassword_Padded = "";

    const string strChars2Use = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>?";
    int nHalfArrCrypto = arrCrypto.Length / 2;

    //Left side
    for (int i = 0; i < nHalfArrCrypto; i++)
    {
        strUserPassword_Padded += strChars2Use[arrCrypto[i] % strChars2Use.Length];
    }

    strUserPassword_Padded += strUserPassword;

    //Right side
    for (int i = nHalfArrCrypto; i < arrCrypto.Length; i++)
    {
        strUserPassword_Padded += strChars2Use[arrCrypto[i] % strChars2Use.Length];
    }

    //For user's password "123"
    //the 'strUserPassword_Padded' becomes:
    //"bwDR]_B>H5t-k:eIq?r_wGBWqWfs#tcAE~DQ5?(Pbj#<+Cw:9(r!B[f_.S<pCjn-123b9l3<Sz^D~>G}v)?NuHT4BZ-pI2$W[kW1e4KO\"`rTg3H`}&jmtrFh1J5c72:})tQ"

    //And now compuse SHA1 on the padded password
    SHA1 sha1 = new SHA1CryptoServiceProvider();
    byte[] bytesInputData = System.Text.Encoding.UTF8.GetBytes(strUserPassword_Padded);
    return sha1.ComputeHash(bytesInputData);
}

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


person ahmd0    schedule 20.03.2013    source источник


Ответы (5)


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

Кроме того, если из пароля получена соль, то идентичные пароли отображаются как идентичные «хэши паролей». Простые пароли, скорее всего, будут отображаться как дубликаты — по сути, вы создаете свою собственную радужную таблицу.

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

person Oliver Charlesworth    schedule 20.03.2013
comment
Нет, это не соль. Я не должен был называть это таким образом. Это просто хлам для заполнения пароля. Я отредактирую это имя переменной... - person ahmd0; 20.03.2013
comment
@ahmd0: На самом деле не имеет значения, как вы это называете. Эффект тот же ;) - person Oliver Charlesworth; 20.03.2013
comment
Эффект, который я пытался передать с помощью этой функции, состоит в том, чтобы предотвратить легкое обратное проектирование полученных хэшей паролей с помощью радужной таблицы. - person ahmd0; 20.03.2013
comment
Мусор не получен из пароля, он статичен. Хотя это все равно довольно бессмысленно. - person diedthreetimes; 20.03.2013
comment
@diedthreetimes Возможно, вы захотите посмотреть еще раз. Скорее всего, это происходит от пароля. - person Jason Watkins; 20.03.2013
comment
@jason, увы, ты прав. Я не смотрел достаточно близко. Хотя это эквивалентно статической случайности. Нет никакого вреда в идентичных паролях, имеющих идентичные хэши паролей, без знания основного ввода в хеш. Тем не менее, пока вы не создаете собственную радужную таблицу, злоумышленник может легко создать ее. - person diedthreetimes; 21.03.2013

Это лишь частично смягчит проблему. То, что вы сделали, по сути, создало хеш-функцию с ключом.

С такой функцией общие радужные таблицы больше не будут применяться, но вы все еще в опасности, если злоумышленник завладеет всей вашей базой данных. В этом случае он может создать новую радужную таблицу на основе этой случайной строки. Используя эту новую таблицу, он имеет высокие шансы взломать хотя бы один аккаунт в вашей системе.

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

Кроме того, я хотел указать, что не имеет значения, сколько «статической» случайности вы добавляете, если случайность остается постоянной.

person diedthreetimes    schedule 20.03.2013
comment
В ПОРЯДКЕ. Ты делаешь доброе дело. Это то, о чем я думал. Просто нужно было какое-то подтверждение. Спасибо. - person ahmd0; 20.03.2013

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

Но если вы хотите использовать только один столбец, ответ будет проще:

Просто используйте pbkdf2, чтобы сделать свой хэш напрямую, создайте 64-битную (8-байтовую) случайную соль, используйте большее количество итераций (4000-10000). Если ваш столбец может содержать только 160 бит (20 байт), тогда сгенерируйте 12 байт (если ваш столбец может содержать больше, я бы увеличил его до 24 байт) и сохраните в своем столбце salt + объединенный хеш.

Таким образом, когда вы сравниваете, вы просто считываете первые 8 байтов, чтобы получить свою соль.

person jbtule    schedule 20.03.2013

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

person Charlie    schedule 20.03.2013
comment
Если вы используете этот метод, вам все равно нужно будет создать отдельное поле соли для второй хеш-функции. - person diedthreetimes; 20.03.2013
comment
Да, это не имеет никакого значения. Я согласен. - person ahmd0; 20.03.2013
comment
Я пропустил часть о базе данных, я сосредоточился исключительно на простом способе повысить безопасность, если вы уже использовали недельный алгоритм хеширования. - person Charlie; 20.03.2013

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

когда они в следующий раз войдут в систему с действительным именем пользователя и паролем (поскольку это только тогда, когда хеш пароля должен измениться или вы делаете массовую принудительную смену пароля для каждого), если нет данных соли, тогда сгенерируйте большую случайную соль, сохраните ее и восстановите хэш из пароля + соль (в идеале используйте что-то лучше, чем SHA1, pbkdf2 необходимо установить выше 10 000, но зависит от ресурсов вашего сервера)

person lee    schedule 21.03.2013