Какой самый простой способ зашифровать пароль, когда я сохраню его в реестре? - PullRequest
55 голосов
/ 17 октября 2008

В настоящее время я пишу это открытым текстом упс! , это собственная программа, так что это не так уж плохо, но я бы хотел сделать это правильно. Как мне зашифровать это при записи в реестр и как расшифровать его?

OurKey.SetValue("Password", textBoxPassword.Text);

Ответы [ 12 ]

121 голосов
/ 17 октября 2008

Вы не расшифровываете пароли аутентификации!

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

byte[] data = System.Text.Encoding.ASCII.GetBytes(inputString);
data = new System.Security.Cryptography.SHA256Managed().ComputeHash(data);
String hash = System.Text.Encoding.ASCII.GetString(data);

Обратимые пароли - это действительно ужасная модель.

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

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

23 голосов
/ 17 октября 2008

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

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

Для хранения хэшей паролей:

a) Генерирует случайное значение соли:

byte[] salt = new byte[32];
System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);

б) Добавьте соль к паролю.

// Convert the plain string pwd into bytes
byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText);
// Append salt to pwd before hashing
byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0, plainTextBytes.Length);
System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length, salt.Length);

в) Хэш комбинированный пароль и соль:

// Create hash for the pwd+salt
System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed();
byte[] hash = hashAlgo.ComputeHash(combinedBytes);

d) Добавьте соль к полученному хешу.

// Append the salt to the hash
byte[] hashPlusSalt = new byte[hash.Length + salt.Length];
System.Buffer.BlockCopy(hash, 0, hashPlusSalt, 0, hash.Length);
System.Buffer.BlockCopy(salt, 0, hashPlusSalt, hash.Length, salt.Length);

e) Сохраните результат в базе данных вашего пользовательского хранилища.

Этот подход означает, что вам не нужно отдельно хранить соль, а затем заново вычислять хеш, используя значение соли и значение пароля в виде открытого текста, полученное от пользователя.

Редактировать : Поскольку необработанные вычислительные мощности становятся все дешевле и быстрее, ценность хеширования - или хелтинга - уменьшается. У Джеффа Этвуда превосходное обновление 2012 года , слишком длинное, чтобы повторить его полностью, в котором говорится:

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

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

13 голосов
/ 24 октября 2015

Том Скотт понял, как правильно (не) хранить пароли на Computerphile.

https://www.youtube.com/watch?v=8ZtInClXe1Q

  1. Если вы вообще можете этого избежать, не пытайтесь хранить пароли самостоятельно. Используйте отдельную, заранее установленную, надежную платформу аутентификации пользователей (например, провайдеры OAuth, Active Directory вашей компании домен и т. д.) вместо.

  2. Если вам необходимо хранить пароли, не следуйте приведенным здесь указаниям. По крайней мере, не без консультации с более свежими и авторитетными публикациями, применимыми к вашему выбранному языку.

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


Правильный способ хранения паролей меняется со временем.

Возможно, чаще, чем некоторые люди меняют нижнее белье.


Все, что сказано, вот некоторые общие рекомендации, которые, будем надеяться, будут полезны некоторое время.

  1. Не шифровать пароли. Любой метод хранения, позволяющий восстанавливать сохраненные данные, по своей сути небезопасен для хранения паролей - включены все формы шифрования.
  2. Обрабатывать пароли точно так, как они были введены пользователем в процессе создания. Все, что вы сделаете с паролем перед его отправкой в ​​модуль криптографии, вероятно, просто ослабит его , Выполнение любого из следующих действий также просто усложняет процесс хранения и проверки пароля, что может вызвать другие проблемы (возможно, даже привнести уязвимости) в будущем.

    • Не преобразовывать все в верхний / нижний регистр.
    • Не удалять пробелы.
    • Не удаляйте недопустимые символы или строки.
    • Не меняйте кодировку текста.
    • Не делайте никаких подстановок символов или строк.
    • Не обрезать пароли любой длины.
  3. Отклонить создание любых паролей, которые не могут быть сохранены без изменений. Укрепление вышесказанного. Если по какой-то причине ваш механизм хранения паролей не может надлежащим образом обрабатывать определенные символы, пробелы, строки или длины паролей, верните ошибку и сообщите пользователю об ограничениях системы, чтобы он мог повторить попытку с паролем, который в них помещается. Для лучшего взаимодействия с пользователем, заранее составьте список этих ограничений. Даже не беспокойтесь, не говоря уже о том, чтобы скрывать список от злоумышленников - они все равно сами все поймут.

  4. Используйте длинную, случайную и уникальную соль для каждой учетной записи. При хранении пароли двух учетных записей не должны выглядеть одинаково, даже если пароли фактически идентичны.
  5. Используйте медленные и криптографически стойкие алгоритмы хеширования, разработанные для использования с паролями. MD5 определенно отсутствует. SHA-1 / SHA-2 не ходят. Но я не собираюсь рассказывать вам, что вы должны использовать здесь. (См. Первый пункт № 2 в этом сообщении.)
  6. Итерируйте столько, сколько вы можете допустить. Хотя ваша система, возможно, будет лучше выполнять свои циклы работы процессора, чем хэш-пароли весь день, люди, которые будут взламывать ваши пароли есть системы, которые этого не делают. Сделайте это настолько жестким для них, насколько сможете, но не сделайте это слишком «тяжелым» для вас.

Самое главное ...

Не просто слушайте кого-либо здесь.

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

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

11 голосов
/ 07 ноября 2008

Вот что вы хотели бы сделать:

OurKey.SetValue("Password", StringEncryptor.EncryptString(textBoxPassword.Text));
OurKey.GetValue("Password", StringEncryptor.DecryptString(textBoxPassword.Text));

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

public class StringEncryptor
{
    private static IKernel _kernel;

    static StringEncryptor()
    {
        _kernel = new StandardKernel(new EncryptionModule());
    }

    public static string EncryptString(string plainText)
    {
        return _kernel.Get<IStringEncryptor>().EncryptString(plainText);
    }

    public static string DecryptString(string encryptedText)
    {
        return _kernel.Get<IStringEncryptor>().DecryptString(encryptedText);
    }
}

Этот следующий класс является непрямым классом, который позволяет вводить различные алгоритмы:

public class EncryptionModule : StandardModule
{
    public override void Load()
    {
        Bind<IStringEncryptor>().To<TripleDESStringEncryptor>();
    }
}

Это интерфейс, который должен быть реализован любым алгоритмом для шифрования / дешифрования строк:

public interface IStringEncryptor
{
    string EncryptString(string plainText);
    string DecryptString(string encryptedText);
}

Это реализация с использованием алгоритма TripleDES:

public class TripleDESStringEncryptor : IStringEncryptor
{
    private byte[] _key;
    private byte[] _iv;
    private TripleDESCryptoServiceProvider _provider;

    public TripleDESStringEncryptor()
    {
        _key = System.Text.ASCIIEncoding.ASCII.GetBytes("GSYAHAGCBDUUADIADKOPAAAW");
        _iv = System.Text.ASCIIEncoding.ASCII.GetBytes("USAZBGAW");
        _provider = new TripleDESCryptoServiceProvider();
    }

    #region IStringEncryptor Members

    public string EncryptString(string plainText)
    {
        return Transform(plainText, _provider.CreateEncryptor(_key, _iv));
    }

    public string DecryptString(string encryptedText)
    {
        return Transform(encryptedText, _provider.CreateDecryptor(_key, _iv));
    }

    #endregion

    private string Transform(string text, ICryptoTransform transform)
    {
        if (text == null)
        {
            return null;
        }
        using (MemoryStream stream = new MemoryStream())
        {
            using (CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write))
            {
                byte[] input = Encoding.Default.GetBytes(text);
                cryptoStream.Write(input, 0, input.Length);
                cryptoStream.FlushFinalBlock();

                return Encoding.Default.GetString(stream.ToArray());
            }
        }
    }
}

Вы можете посмотреть мое видео и скачать код для этого по адресу: http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html

10 голосов
/ 17 октября 2008

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

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

Если это просто для аутентификации, то достаточно будет использовать хеш.

9 голосов
/ 17 октября 2008

Если вы хотите иметь возможность расшифровывать пароль, я думаю, что самый простой способ - использовать DPAPI (режим хранилища пользователей) для шифрования / дешифрования. Таким образом, вам не нужно возиться с ключами шифрования, хранить их где-нибудь или жестко кодировать их в своем коде - в обоих случаях кто-то может обнаружить их, заглянув в реестр, настройки пользователя или используя Reflector.

В противном случае используйте хеши SHA1 или MD5, как здесь говорили другие.

6 голосов
/ 23 марта 2009

Как сказал ligget78, DPAPI будет хорошим способом хранения паролей. Проверьте класс ProtectedData на MSDN , например, для использования.

5 голосов
/ 28 мая 2011

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

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

Итак, я написал процесс, который сделает это в упрощенной форме. Я надеюсь, что этот код кому-то полезен. Насколько я знаю, я могу использовать это в другое время для другой компании / сайта.

public string GenerateAPassKey(string passphrase)
    {
        // Pass Phrase can be any string
        string passPhrase = passphrase;
        // Salt Value can be any string(for simplicity use the same value as used for the pass phrase)
        string saltValue = passphrase;
        // Hash Algorithm can be "SHA1 or MD5"
        string hashAlgorithm = "SHA1";
        // Password Iterations can be any number
        int passwordIterations = 2;
        // Key Size can be 128,192 or 256
        int keySize = 256;
        // Convert Salt passphrase string to a Byte Array
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        // Using System.Security.Cryptography.PasswordDeriveBytes to create the Key
        PasswordDeriveBytes pdb = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);
        //When creating a Key Byte array from the base64 string the Key must have 32 dimensions.
        byte[] Key = pdb.GetBytes(keySize / 11);
        String KeyString = Convert.ToBase64String(Key);

        return KeyString;
    }

 //Save the keystring some place like your database and use it to decrypt and encrypt
//any text string or text file etc. Make sure you dont lose it though.

 private static string Encrypt(string plainStr, string KeyString)        
    {            
        RijndaelManaged aesEncryption = new RijndaelManaged();
        aesEncryption.KeySize = 256;
        aesEncryption.BlockSize = 128;
        aesEncryption.Mode = CipherMode.ECB;
        aesEncryption.Padding = PaddingMode.ISO10126;
        byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString);
        aesEncryption.Key = KeyInBytes;
        byte[] plainText = ASCIIEncoding.UTF8.GetBytes(plainStr);
        ICryptoTransform crypto = aesEncryption.CreateEncryptor();
        byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
        return Convert.ToBase64String(cipherText);
    }

 private static string Decrypt(string encryptedText, string KeyString) 
    {
        RijndaelManaged aesEncryption = new RijndaelManaged(); 
        aesEncryption.KeySize = 256;
        aesEncryption.BlockSize = 128; 
        aesEncryption.Mode = CipherMode.ECB;
        aesEncryption.Padding = PaddingMode.ISO10126;
        byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString);
        aesEncryption.Key = KeyInBytes;
        ICryptoTransform decrypto = aesEncryption.CreateDecryptor(); 
        byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length); 
        return ASCIIEncoding.UTF8.GetString(decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)); 
    }

 String KeyString = GenerateAPassKey("PassKey");
 String EncryptedPassword = Encrypt("25Characterlengthpassword!", KeyString);
 String DecryptedPassword = Decrypt(EncryptedPassword, KeyString);
5 голосов
/ 17 октября 2008

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

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

1 голос
/ 17 октября 2008

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

Ответ Оли также хорош, поскольку он показывает, как вы можете создать хеш для строки.

...