当前位置:  开发笔记 > 编程语言 > 正文

将密码保存到注册表时,加密密码的最简单方法是什么?

如何解决《将密码保存到注册表时,加密密码的最简单方法是什么?》经验,为你挑选了9个好方法。

目前我用明文哎呀写它!,这是一个内部计划所以它并没有那么糟糕,但我想做得对.在写入注册表时我应该如何加密这个以及如何解密呢?

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

Oli.. 125

您不解密身份验证密码!

使用类似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:我以为我们刚才谈的是前线认证.当然,有些情况下你想要为其他需要可逆的东西加密密码,但是应该有一个单向锁定(除了极少数例外).

我已经升级了散列算法,但为了获得最佳强度,您需要保留私有盐并散列之前将其添加到输入中.比较时你会再次这样做.这增加了另一层,使得某人更难以扭转.



1> Oli..:
您不解密身份验证密码!

使用类似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:我以为我们刚才谈的是前线认证.当然,有些情况下你想要为其他需要可逆的东西加密密码,但是应该有一个单向锁定(除了极少数例外).

我已经升级了散列算法,但为了获得最佳强度,您需要保留私有盐并散列之前将其添加到输入中.比较时你会再次这样做.这增加了另一层,使得某人更难以扭转.


**请不要推荐MD5.**[MD5不能安全地保护密码.](http://codahale.com/how-to-safely-store-a-password/)[MD5会让你和你的公司在新闻中出于错误的原因.](http://www.h-online.com/security/news/item/Password-leaks-bigger-than-first-thought-1614516.html)[MD5很容易我重复一遍:[MD5很容易破解.](http://stacksmashing.net/2010/11/15/cracking-in-the- cloud-amazons-new-ec2-gpu-instances /)**出于同样的原因,不要推荐使用SHA-1**.****推荐PBKDF2,bcrypt,甚至是scrypt.**
通常,存储密码是一个坏主意,但有正当理由这样做.也许不在注册表中,但是......例如,我有一个需要使用服务ID /密码访问Web服务的Web应用程序.我将加密存储在Web配置中.
我对C#在代码中替代编辑感到不舒服,但显然我鼓励你至少在你的答案中添加一个注释,说明使用MD5哈希密码的已知危险.
"让密码可逆是一个非常可怕的模型." - 如果要保存对外部服务进行身份验证所需的密码,则别无选择.CredUI用于加密密码的安全存储.
这个答案是["c#hash password example"](https://www.google.com/webhp?q=c%23%20hash%20password%20example)的热门话题.请想想孩子们.
@Mark:所以他可以通过提高答案来解决投票失败的原因.
@NickChammas提交编辑而不是评论.它就像一个代码示例.

2> DOK..:

还请考虑"腌制"你的哈希(不是烹饪概念!).基本上,这意味着在散列之前将一些随机文本附加到密码.

" 如果您的凭证存储受到损害,盐值有助于减缓攻击者执行字典攻击的速度,从而为您提供额外的时间来检测并做出妥协. "

存储密码哈希值:

a)生成随机盐值:

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

b)将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);

c)哈希组合密码和盐:

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

d)将salt附加到生成的哈希值.

// 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)将结果存储在用户存储数据库中.

这种方法意味着您不需要单独存储salt,然后使用salt值和从用户获得的纯文本密码值重新计算哈希值.

编辑:随着原始计算能力变得更便宜和更快,哈希 - 或盐渍哈希 - 的价值已经下降.杰夫阿特伍德有一个非常好的2012年更新太长,不能在这里重复,其中指出:

这(使用盐渍哈希)将提供比任何实际安全更多的安全幻觉.既然你需要salt和hash算法的选择来生成散列,并检查散列,那么攻击者不太可能拥有一个而不是另一个.如果您已被攻击者攻击者拥有您的密码数据库,那么可以合理地假设他们拥有或者可以获得您的秘密隐藏的盐.

安全的第一条规则是始终承担并计划最坏的情况.您是否应该使用盐,理想情况下每个用户使用盐?当然,这绝对是一个很好的做法,至少它可以让你消除两个拥有相同密码的用户的歧义.但是现在,只有盐才能让你不再愿意花费几千美元购买视频卡硬件,如果你认为它们可以,你就会陷入困境.



3> Iszi..:

汤姆斯科特在他的关于如何(不)存储密码的报道中,在Computerphile上做得对.

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

    如果您可以完全避免它,请不要尝试自己存储密码.使用单独的,预先建立的,值得信赖的用户身份验证平台(例如:OAuth提供商,您公司的Active Directory域等).

    如果您必须存储密码,请不要遵循此处的任何指导.至少,并非没有咨询适用于您选择的语言的更新近的和有信誉的出版物.

这里肯定有很多聪明人,甚至可能给出一些很好的指导.但是,当你读到这篇文章时,这里的所有答案(包括这个答案)都已经过时了.


存储密码的正确方法会随着时间而变化.

可能比一些人改变内衣更频繁.


所有这一切,这里有一些一般指导,希望有一段时间可以保持有用.

    不要加密密码.任何允许恢复存储数据的存储方法本身就不安全以保存密码 - 包括所有形式的加密.

    在创建过程中完全按照用户输入的密码处理密码.在将密码发送到加密模块之前对密码所做的任何操作都可能会削弱密码.执行以下任何操作也会增加密码存储和验证过程的复杂性,这可能会导致其他问题(甚至可能引入漏洞).

    不要转换为全大写/全小写.

    不要删除空格.

    不要删除不可接受的字符或字符串.

    不要更改文本编码.

    不要做任何字符或字符串替换.

    不要截断任何长度的密码.

    拒绝创建任何无需修改即无法存储的密码.加强以上.如果出于某种原因,您的密码存储机制无法正确处理某些字符,空格,字符串或密码长度,则会返回错误并让用户了解系统的限制,以便他们可以使用适合其中的密码重试.为了获得更好的用户体验,请预先列出用户可以访问的那些限制.甚至不用担心,更别提工作了,将列表从攻击者那里隐藏起来 - 无论如何,他们都会轻易地自己解决这个问题.

    为每个帐户使用长,随机且唯一的盐.即使密码实际上相同,也不会有两个帐户的密码在存储中看起来相同.

    使用专为密码设计的慢速和加密强哈希算法.MD5肯定是出局的.SHA-1/SHA-2是禁止的.但我不会告诉你你应该在这里使用什么.(参见本文中的第一个#2子弹.)

    尽可能多地迭代.虽然您的系统可能与处理器周期有更好的关系,而不是整天的哈希密码,但是破解密码的人却没有系统.尽可能地让它们变得坚硬,而不是让它"太难".


最重要的是...

不要只听这里的任何人.

去查找有关您所选语言的正确密码存储方法的信誉良好且最新的出版物.实际上,在解决一种方法之前,您应该从多个单独的来源中找到多个最近的出版物.

这里的每个人(包括我自己)所说的一切都极有可能已经被更好的技术所取代,或者被新开发的攻击方法变得不安全.去找一些更可能没有的东西.



4> Jamie Wright..:

这是你想要做的:

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

您可以使用以下类来完成此操作.这个类是泛型类,是客户端端点.它使用Ninject实现各种加密算法的IOC.

public class StringEncryptor
{
    private static IKernel _kernel;

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

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

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

下一个类是ninject类,它允许您注入各种算法:

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

这是任何算法需要实现的用于加密/解密字符串的接口:

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


@pst他正在演示如何使用任何加密方法使您的实现可插入,而不是推荐任何特定方法.随着加密破解技术的不断发展,能够将其交换出来是件好事.

5> Bogdan Maxim..:

一种选择是存储密码的散列(SHA1,MD5)而不是明文密码,并且只要您想查看密码是否良好,只需将其与该散列进行比较即可.

如果您需要安全存储(例如,用于连接服务的密码),则问题会更加复杂.

如果只是用于身份验证,那么使用哈希就足够了.


SHA1/MD5用于密码?不,地狱没有.
@Iszi - 问题和答案来自8年前

6> liggett78..:

如果您希望能够解密密码,我认为最简单的方法是使用DPAPI(用户存储模式)来加密/解密.这样您就不必使用加密密钥,将它们存储在某处或在代码中对它们进行硬编码 - 在这两种情况下,有人可以通过查看注册表,用户设置或使用Reflector来发现它们.

否则使用哈希SHA1或MD5就像其他人所说的那样.



7> Beau..:

就像ligget78所说,DPAPI是存储密码的好方法.查看MSDN上的ProtectedData类以获取示例用法.



8> Deathstalker..:

我到处寻找加密和解密过程的一个很好的例子,但是大多数都过于复杂。

无论如何,有人可能有许多原因想要解密某些文本值(包括密码)。我需要在当前正在使用的网站上解密密码的原因是,他们希望确保在过期时何时有人被迫更改密码,我们不允许他们使用相同密码的紧密变体来更改密码他们在过去x个月中使用过。

因此,我编写了一个简化的过程。我希望这段代码对某人有益。就我所知,我可能最终会在另一个时间将其用于其他公司/站点。

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);



9> Joe..:

如果它是您的应用程序用于身份验证的密码,则按其他人的建议散列密码.

如果您要存储外部资源的密码,您通常希望能够提示用户提供这些凭据,并让他有机会安全地保存这些凭据.Windows为此提供了凭据UI(CredUI) - 有许多示例显示如何在.NET中使用它,包括MSDN上的这个.

推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有