web-dev-qa-db-ja.com

パスワードをレジストリに保存するときにパスワードを暗号化する最も簡単な方法は何ですか?

現在、私は平文で書いていますoops!、それは社内プログラムですので、それほど悪くはありませんが、私はそれを正しくやりたいです。レジストリへの書き込み時にこれを暗号化するにはどうすればよいですか?また、復号化するにはどうすればよいですか?

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

認証パスワードを解読しないでください!

SHA256プロバイダーなどを使用してハッシュし、チャレンジする必要がある場合は、ユーザーからの入力をハッシュし、2つのハッシュが一致するかどうかを確認します。

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

パスワードを元に戻すことは、really恐ろしいモデルです。

編集2:私たちは最前線の認証について話しているだけだと思いました。もちろん、元に戻す必要がある他のもののためにパスワードを暗号化したい場合もありますが、その上に一方向ロックが必要です(ごくわずかな例外を除きます)。

ハッシュアルゴリズムをアップグレードしましたが、可能な限り最高の強度を維持するために、 プライベートなソルトを入力に追加してbeforeハッシュします) it 。比較すると、これを再度行うことになります。これにより、別のレイヤーが追加され、誰かがリバースするのがさらに難しくなります。

123
Oli

ハッシュの「塩漬け」も考慮してください(料理の概念ではありません!)。基本的に、これはハッシュする前にパスワードにランダムなテキストを追加することを意味します。

" ソルト値は、資格情報ストアが侵害された場合に攻撃者が辞書攻撃を実行するのを遅らせるのに役立ち、侵害を検出して対応するための追加の時間を与えます。 "

パスワードハッシュを保存するには:

a)ランダムなソルト値を生成します。

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

b)パスワードにソルトを追加します。

// 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)結果のハッシュにソルトを追加します。

// 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)結果をユーザーストアデータベースに保存します。

このアプローチは、ソルトを個別に保存し、ソルト値とユーザーから取得したプレーンテキストのパスワード値を使用してハッシュを再計算する必要がないことを意味します。

Edit:未加工の計算能力がより安く、より速くなるにつれて、ハッシュの値-またはハッシュのソルティング-は減少しました。 Jeff Atwoodには2012年の優れたアップデートがあります 長すぎてここで全体を繰り返すことはできません。

これは(ソルトハッシュを使用して)実際のセキュリティよりもセキュリティの幻想を提供します。ハッシュを生成し、ハッシュをチェックするにはソルトとハッシュアルゴリズムの選択の両方が必要なので、攻撃者が一方を持ち、もう一方を持たない可能性は低いです。攻撃者がパスワードデータベースを持っているという点まで侵害された場合、彼らはあなたの秘密の隠された塩を持っている、または手に入れることができると仮定するのが合理的です。

セキュリティの最初のルールは、常に最悪の事態を想定して計画することです。ソルト、理想的にはユーザーごとにランダムなソルトを使用すべきですか?確かに、これは間違いなく良い習慣であり、少なくとも同じパスワードを持っている2人のユーザーを明確にすることができます。しかし、最近では、塩だけでは、ビデオカードハードウェアに数千ドルを費やすことを望んでいる人からあなたを救うことはできません。

23
DOK

トムスコットは、Computerphileでパスワードを保存する方法(しない)についての彼の報道でそれを正しく理解した。

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

  1. まったく回避できる場合は、自分でパスワードを保存しようとしないでください。事前に確立された、信頼できる別のユーザー認証プラットフォームを使用します(例:OAuthプロバイダー、代わりに会社のActive Directoryドメインなど)。

  2. パスワードを保存する必要がある場合は、ここのガイダンスに従わないでください。少なくとも、選択した言語に該当する最新の評判のよい出版物も参照することなく。

確かにここには賢い人がたくさんいますし、おそらく良い指導さえあります。しかし、あなたがこれを読むまでに、ここでのすべての回答(これを含む)がすでに古くなっている可能性が高いです。


パスワードを保存する正しい方法は時間とともに変化します。

おそらく下着を交換する人よりも頻繁に。


とはいえ、ここではしばらくの間役に立つと思われる一般的なガイダンスを示します。

  1. パスワードを暗号化しない。保管されたデータの回復を可能にする保管方法は、パスワードを保持するために本質的に安全ではありません。
  2. 作成プロセス中にユーザーが入力したとおりにパスワードを処理します。パスワードを暗号化モジュールに送信する前に行うことは、おそらくパスワードを弱めるだけです。また、次のいずれかを実行すると、パスワードの保存と検証プロセスが複雑になり、他の問題が発生する可能性があります(おそらく脆弱性が導入される可能性もあります)。

    • すべて大文字/すべて小文字に変換しないでください。
    • 空白を削除しないでください。
    • 許容できない文字や文字列を削除しないでください。
    • テキストエンコーディングを変更しないでください。
    • 文字や文字列の置換を行わないでください。
    • どんな長さのパスワードも切り捨てないでください。
  3. 変更せずに保存できないパスワードの作成を拒否します。上記の強化。何らかの理由でパスワードストレージメカニズムが特定の文字、空白、文字列、またはパスワードの長さを適切に処理できない場合は、エラーを返し、ユーザーにシステムの制限を知らせて、それらに適合するパスワードで再試行できるようにします。ユーザーエクスペリエンスを向上させるには、これらの制限のリストを事前にユーザーがアクセスできるようにします。リストを攻撃者から隠すことはもちろん、気にすることもなく、心配する必要はありません。

  4. アカウントごとに長くてランダムな一意のソルトを使用します。パスワードが実際に同一であっても、2つのアカウントのパスワードが同じに見えることはありません。
  5. パスワードで使用するために設計された低速で暗号強度の高いハッシュアルゴリズムを使用します。MD5は確実に廃止されました。 SHA-1/SHA-2は禁止です。しかし、ここでshouldを使用するかどうかについては説明しません。 (この投稿の最初の2番目の箇条書きを参照してください。)
  6. 許容範囲内で繰り返します。システムは、1日中ハッシュパスワードよりもプロセッササイクルの方が優れている場合がありますが、パスワードにはないシステムがあります。できる限り「ハード」にしすぎずに、できる限りハードにします。

最も重要なこと...

ここで誰かに聞いてはいけません。

選択した言語のパスワード保存の適切な方法に関する評判の良い最新の出版物をご覧ください。実際には、1つの方法を決定する前に、複数の別個のソースからの複数の最近の出版物が一致していることを確認する必要があります。

ここにいるすべての人(自分も含めて)が言ったことはすべて、既により優れた技術に取って代わられたり、新しく開発された攻撃方法によって安全性が低下したりする可能性が非常に高いです。おそらくないものを見つけてください。

14
Iszi

これはあなたがやりたいことです:

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<IStringEncryptor>().EncryptString(plainText);
    }

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

この次のクラスは、さまざまなアルゴリズムを挿入できるninjectクラスです。

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

11
Jamie Wright

1つのオプションは、クリアテキストパスワードの代わりにパスワードのハッシュ(SHA1、MD5)を保存し、パスワードが適切かどうかを確認したい場合は、そのハッシュと比較するだけです。

安全なストレージが必要な場合(たとえば、サービスへの接続に使用するパスワード用)、問題はより複雑です。

認証のためだけのものであれば、ハッシュを使用するだけで十分です。

10
Bogdan Maxim

パスワードを解読できるようにする場合、DPAPI(ユーザーストアモード)を使用して暗号化/解読するのが最も簡単な方法だと思います。このように、暗号化キーをいじったり、どこかに保存したり、コードにハードコーディングしたりする必要はありません。どちらの場合も、レジストリ、ユーザー設定、またはReflectorを調べることで、誰かがそれらを発見できます。

それ以外の場合は、他の人がここで言っているようにハッシュSHA1またはMD5を使用します。

9
liggett78

Ligget78が言ったように、DPAPIはパスワードの保存に適した方法です。 MSDNのProtectedDataクラスをご覧ください 使用例。

6
Beau

暗号化と復号化のプロセスの良い例を探しましたが、ほとんどは非常に複雑でした。

とにかく、誰かがパスワードを含むいくつかのテキスト値を解読したいかもしれない多くの理由があります。現在作業中のサイトでパスワードを復号化する必要があるのは、誰かがパスワードの有効期限が切れたときにパスワードの変更を強制された場合に、同じパスワードの近い亜種で変更できないようにするためです。過去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);
6
Deathstalker

それがアプリケーションによる認証に使用されるパスワードである場合、他の人が示唆するようにパスワードをハッシュします。

外部リソースのパスワードを保存している場合、多くの場合、ユーザーにこれらの資格情報を要求し、ユーザーに安全に保存する機会を与えたいと思うでしょう。 Windowsは、この目的のためにCredentials UI(CredUI)を提供します。 MSDN上のこの など、.NETでこれを使用する方法を示すいくつかのサンプルがあります。

5
Joe

これ以上のものが必要な場合、たとえばデータベースへの接続用に接続文字列を保護する場合は、この article をチェックしてください。これにより、最適な「オプション」が提供されます。

Oliの答えも優れています。文字列のハッシュを作成する方法を示しています。

1
Bogdan Maxim

..NETは、System.Security.Cryptography名前空間に含まれるクラスで暗号化サービスを提供します。

0
osp70