短い答え
なぜ私はただ言うことができないのですか?
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は、Data Protection 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内には、互換性のためにプレーン文字列を受け入れ続け、すぐにそれを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に文字列を取得できますか?さて、あなたがしなければならないことは、そもそもStringにパスワードを持たせることをやめることです。あなたはそれを別のものに入れる必要がありました。でも、Char[]
配列は参考になります。
これは、各文字を追加して、完了時にプレーンテキストをワイプできる場合です。
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
あなたはに保存されたパスワード必要いくつかのあなたは拭くことができるという記憶を。そこからSecureStringにロードします。
tl; dr:ZeroStringと同等の機能を提供するSecureStringが存在します。
一部の人々は、デバイスがロックされているときにメモリからユーザーのパスワードをワイプしたり、認証後にキーストロークをメモリからワイプしたりするポイントを理解しません。それらの人々はSecureStringを使用しません。
SecureString
は新しい開発を推奨しなくなりました:github.com/dotnet/platform-compat/blob/master/docs/DE0001.md