Ошибка в криптографии в.NET 4.0

Сегодня я переместил свое веб-приложение на.net 4.0, и Forms Auth просто перестал работать. После нескольких часов копания в моем SqlMembershipProvider (упрощенная версия встроенного SqlMembershipProvider) я обнаружил, что хеш HMACSHA256 не согласован. Это метод шифрования:

internal string EncodePassword(string pass, int passwordFormat, string salt)
{
    if (passwordFormat == 0) // MembershipPasswordFormat.Clear
        return pass;

    byte[] bIn = Encoding.Unicode.GetBytes(pass);
    byte[] bSalt = Convert.FromBase64String(salt);
    byte[] bAll = new byte[bSalt.Length + bIn.Length];
    byte[] bRet = null;

    Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
    Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
    if (passwordFormat == 1)
    { // MembershipPasswordFormat.Hashed
        HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );
        bRet = s.ComputeHash(bAll);
    } else
    {
        bRet = EncryptPassword( bAll );
    }

    return Convert.ToBase64String(bRet);
}

Передача одного и того же пароля и соли дважды возвращает разные результаты!!! Он отлично работал в.NET 3.5

Кто-нибудь знает о каких-либо серьезных изменениях, или это известная ошибка?

ОБНОВЛЕНИЕ: Когда я указываю SHA512 в качестве алгоритма хеширования, все работает нормально, поэтому я считаю, что это ошибка в реализации алгоритма хеширования HMACSHA256 в.NET 4.0

Спасибо! Андрей

2 ответа

Решение

Я считаю, что в.net 4.0 произошли некоторые изменения, связанные с безопасностью, посмотрите на это...

http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/whitepapers/aspnet4/breaking-changes

Первое, что бросается в глаза, это...

Алгоритм хеширования по умолчанию теперь HMACSHA256

ASP.NET использует как алгоритмы шифрования, так и алгоритмы хеширования для защиты данных, таких как файлы cookie проверки подлинности форм и состояние просмотра. По умолчанию ASP.NET 4 теперь использует алгоритм HMACSHA256 для операций хеширования с файлами cookie и состояния просмотра. В более ранних версиях ASP.NET использовался более старый алгоритм HMACSHA1.

Это может повлиять на ваши приложения, если вы запустите смешанную среду ASP.NET 2.0/ASP.NET 4, в которой такие данные, как файлы cookie проверки подлинности форм, должны работать в разных версиях.NET Framework. Чтобы настроить веб-приложение ASP.NET 4 для использования более старого алгоритма HMACSHA1, добавьте следующий параметр в файл Web.config:

      <machineKey validation="SHA1" />

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

Сказав это, M$, возможно, удалил тот, который вы используете, так что это может быть причиной, чёрт побери... я только что понял, что мне нужно проверить мою CMS ... это не пришло мне в голову.

Спасибо за внимание, надеюсь, мои мысли помогут нам обоим!!!

Я тоже столкнулся с этой проблемой.

В моей ситуации конечная цель состояла в том, чтобы иметь возможность динамически устанавливать connectionString (вместо жестко заданного в web.config). Я сделал это, загрузив исходный код MS для провайдеров ASP.NET и изменив некоторые внутренние функции для получения строки подключения.

Тем не менее, все это было для.NET 2.0 и выглядит так же, как код, который Андрей выложил выше. Как только я все это установил, я заметил, что не могу войти на свой сайт. Поэтому после поиска я нашел этот пост. Спасибо!

Я скачал код.NET Framework 4.0 и (если кто-то хочет знать) вот новую версию метода EncodePassword. Я планирую скопировать это в мою старую версию SqlMembershipProvider, чтобы я мог использовать новые методы шифрования и снова иметь возможность войти на свой сайт ASP.NET 4.0!

    private string EncodePassword(string pass, int passwordFormat, string salt)
    { 
        if (passwordFormat == 0) // MembershipPasswordFormat.Clear
            return pass;

        byte[] bIn = Encoding.Unicode.GetBytes(pass); 
        byte[] bSalt = Convert.FromBase64String(salt);
        byte[] bRet = null; 

        if (passwordFormat == 1)
        { // MembershipPasswordFormat.Hashed 
            HashAlgorithm hm = GetHashAlgorithm();
            if (hm is KeyedHashAlgorithm) {
                KeyedHashAlgorithm kha = (KeyedHashAlgorithm) hm;
                if (kha.Key.Length == bSalt.Length) { 
                    kha.Key = bSalt;
                } else if (kha.Key.Length < bSalt.Length) { 
                    byte[] bKey = new byte[kha.Key.Length]; 
                    Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
                    kha.Key = bKey; 
                } else {
                    byte[] bKey = new byte[kha.Key.Length];
                    for (int iter = 0; iter < bKey.Length; ) {
                        int len = Math.Min(bSalt.Length, bKey.Length - iter); 
                        Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
                        iter += len; 
                    } 
                    kha.Key = bKey;
                } 
                bRet = kha.ComputeHash(bIn);
            }
            else {
                byte[] bAll = new byte[bSalt.Length + bIn.Length]; 
                Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
                Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length); 
                bRet = hm.ComputeHash(bAll); 
            }
        } else { 
            byte[] bAll = new byte[bSalt.Length + bIn.Length];
            Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
            Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
            bRet = EncryptPassword(bAll, _LegacyPasswordCompatibilityMode); 
        }

        return Convert.ToBase64String(bRet); 
    }

Редактировать: Попытка скопировать этот метод в старую версию SqlMembershipProvider была плохой идеей. Слишком многое изменилось.:(

Другие вопросы по тегам