簡潔な答え
なぜ私はただ言うことができないのですか:
SecureString password = new SecureString("password");
今、あなたはpassword
記憶にあるからです。それを消去する方法はありません-これはまさにSecureStringのポイントです。
長い答え
SecureStringが存在する理由は、使い終わった機密データを消去するためにZeroMemoryを使用できないためです。CLRが原因で発生する問題を解決するために存在します。
通常のネイティブアプリケーションでは、次のように呼び出しますSecureZeroMemory
。
メモリのブロックをゼロで埋めます。
注: SecureZeroMemory は と同じですがZeroMemory
、コンパイラはそれを最適化しません。
問題は、.NET 内で呼び出しできないことです。また、.NET では文字列は不変です。他の言語でできるように、文字列の内容を上書きすることさえできません。ZeroMemory
SecureZeroMemory
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
それで、あなたは何ができますか?.NET で、使い終わったパスワードやクレジット カード番号をメモリから消去する機能をどのように提供すればよいでしょうか?
これを行う唯一の方法は、文字列をネイティブメモリ ブロックに配置し、そこで を呼び出すことZeroMemory
です。次のようなネイティブ メモリ オブジェクト:
- BSTR
- HGLOBAL
- CoTaskMem アンマネージ メモリ
SecureString は失われた能力を取り戻します
.NET では、使い終わった文字列をワイプすることはできません。
- それらは不変です。その内容を上書きすることはできません
- あなた
Dispose
はそれらのことはできません
- それらのクリーンアップはガベージコレクターのなすがままです
SecureString は、文字列の安全性を確保し、必要なときに確実にクリーンアップできるようにする方法として存在します。
あなたは質問をしました:
なぜ私はただ言うことができないのですか:
SecureString password = new SecureString("password");
今、あなたはpassword
記憶にあるからです。それを拭く方法はありません。CLRがたまたまそのメモリを再利用することを決定するまで、それはそこにとどまります。あなたは私たちを最初の場所に戻してくれました。削除できないパスワードを持つ実行中のアプリケーションと、メモリ ダンプ (またはプロセス モニター) がパスワードを確認できる場所。
SecureString はデータ保護 API を使用して、暗号化された文字列をメモリに格納します。そうすれば、文字列はスワップファイル、クラッシュ ダンプ、さらには同僚が見ているローカル変数ウィンドウにも存在しません。
パスワードの読み方は?
次に問題です。文字列を操作するにはどうすればよいですか? 次のようなメソッドは絶対に必要ありません。
String connectionString = secureConnectionString.ToString()
これで、元の場所に戻ったからです。つまり、パスワードを取り除くことはできません。機密性の高い文字列をメモリから消去できるように、開発者に機密文字列を正しく処理させる必要があります。
そのため、.NET には、SecureString をアンマネージ メモリにマーシャリングするための 3 つの便利なヘルパー関数が用意されています。
文字列をアンマネージ メモリ BLOB に変換し、処理してから、もう一度ワイプします。
一部の API はSecureStringsを受け入れます。たとえば、ADO.net 4.5 では、SqlConnection.CredentialはセットSqlCredentialを取ります。
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
接続文字列内でパスワードを変更することもできます。
SqlConnection.ChangePassword(connectionString, cred, newPassword);
また、.NET 内には、互換性のためにプレーンな String を受け入れ続け、すぐにそれを SecureString に変換する場所がたくさんあります。
テキストを SecureString に入れる方法は?
これはまだ問題を残しています:
そもそもSecureStringにパスワードを取得するにはどうすればよいですか?
これは課題ですが、ポイントはセキュリティについて考えさせることです。
機能がすでに提供されている場合もあります。たとえば、WPF PasswordBoxコントロールは、入力されたパスワードをSecureStringとして直接返すことができます。
PasswordBox が現在保持しているパスワードをSecureStringとして取得します。
生の文字列を渡していたところはどこでも、SecureString が String と互換性がないことを型システムが訴えているため、これは役に立ちます。SecureString を通常の文字列に変換する前に、できるだけ長くしたいと考えています。
SecureString の変換は簡単です。
- SecureStringToBSTR
- PtrToStringBSTR
次のように:
private static string CreateString(SecureString secureString)
{
IntPtr intPtr = IntPtr.Zero;
if (secureString == null || secureString.Length == 0)
{
return string.Empty;
}
string result;
try
{
intPtr = Marshal.SecureStringToBSTR(secureString);
result = Marshal.PtrToStringBSTR(intPtr);
}
finally
{
if (intPtr != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(intPtr);
}
}
return result;
}
彼らは本当にあなたにそれをしてほしくありません。
しかし、文字列を SecureString に入れるにはどうすればよいですか? まず、文字列にパスワードを含めるのをやめる必要があります。あなたはそれを何か他のものにする必要がありました。配列でもChar[]
役に立ちます。
そのとき、各文字を追加し、完了したらプレーンテキストを消去できます。
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
消去できるメモリにパスワードを保存する必要があります。そこから SecureString にロードします。
tl;dr: SecureStringは、 ZeroMemoryと同等のものを提供するために存在します。
一部の人々は、デバイスがロックされているときにメモリからユーザーのパスワードをワイプしたり、認証後にキーストロークをメモリからワイプしたりする意味を理解していません。それらの人々はSecureStringを使用しません。