185

.NET の SecureString の目的を理解しようとしています。MSDN から:

System.String クラスのインスタンスは不変であり、不要になった場合、プログラムでガベージ コレクションをスケジュールすることはできません。つまり、インスタンスは作成後は読み取り専用であり、インスタンスがコンピューターのメモリからいつ削除されるかを予測することはできません。したがって、String オブジェクトにパスワード、クレジット カード番号、個人データなどの機密情報が含まれている場合、アプリケーションはコンピューターのメモリからデータを削除できないため、使用後に情報が漏洩する危険性があります。

SecureString オブジェクトは、テキスト値を持つという点で String オブジェクトに似ています。ただし、SecureString オブジェクトの値は自動的に暗号化され、アプリケーションが読み取り専用としてマークするまで変更でき、アプリケーションまたは .NET Framework ガベージ コレクターによってコンピューター メモリから削除できます。

SecureString のインスタンスの値は、インスタンスの初期化時または値の変更時に自動的に暗号化されます。MakeReadOnly メソッドを呼び出すことで、アプリケーションはインスタンスを不変にし、それ以上の変更を防ぐことができます。

自動暗号化は大きな見返りですか?

そして、なぜ私はただ言うことができないのですか:

SecureString password = new SecureString("password");

それ以外の

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

SecureString のどの側面が欠けていますか?

4

11 に答える 11

108

現在使用しているフレームワークの一部SecureString:

主な目的は、攻撃対象領域を排除することではなく、削減することです。SecureStringsRAM に「固定」されているため、ガベージ コレクターはそれを移動したり、コピーを作成したりしません。また、プレーン テキストがスワップ ファイルやコア ダンプに書き込まれないようにします。暗号化は難読化に似ており、暗号化と復号化に使用される対称キーを見つけることができるハッカーを止めることはできません。

他の人が言ったように、SecureString文字ごとに作成しなければならない理由は、それ以外の場合の最初の明らかな欠陥のためです。おそらく、秘密の値をプレーン文字列として既に持っているので、ポイントは何ですか?

SecureStrings は鶏が先か卵が先かという問題を解決するための最初のステップです。そのため、現在のほとんどのシナリオでは、それらを使用するために通常の文字列に戻す必要がありますが、フレームワーク内のそれらの存在は、将来 - 少なくとも、プログラムが弱いリンクである必要がなくなるまで。

于 2008-09-26T19:20:38.990 に答える
37

編集SecureStringを使用しないでください

現在のガイダンスでは、クラスを使用すべきではないと述べています。詳細は次のリンクにあります: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

記事から:

DE0001: SecureString は使用しないでください

動機

  • の目的は、SecureStringシークレットがプレーン テキストとしてプロセス メモリに保存されるのを回避することです。
  • ただし、Windows でもSecureString、OS の概念としては存在しません。
    • ウィンドウがプレーンテキストを短くするだけです。.NET は文字列をプレーン テキスト表現に変換する必要があるため、完全には防止できません。
    • 利点は、プレーン テキスト表現がインスタンスとしてぶらぶらしないことSystem.Stringです。ネイティブ バッファーの有効期間は短くなります。
  • .NET Framework を除いて、配列の内容は暗号化されません。
    • .NET Framework では、内部の char 配列の内容が暗号化されます。.NET は、API がないか、キー管理の問題があるため、すべての環境で暗号化をサポートしているわけではありません。

おすすめ

SecureString新しいコードには使用しないでください。コードを .NET Core に移植するときは、配列の内容がメモリ内で暗号化されていないことを考慮してください。

資格情報を処理する一般的な方法は、それらを回避し、代わりに証明書や Windows 認証などの他の認証手段に依存することです。

編集終了:以下の元の要約

素晴らしい答えがたくさんあります。これまでに議論された内容の簡単な概要を次に示します。

Microsoft は、機密情報 (クレジット カード、パスワードなど) のセキュリティを強化するために、SecureString クラスを実装しました。以下を自動的に提供します。

  • 暗号化 (メモリ ダンプまたはページ キャッシュの場合)
  • メモリにピン留めする
  • 読み取り専用としてマークする機能 (それ以上の変更を防ぐため)
  • 定数文字列を渡すことを許可しないことによる安全な構築

現在、SecureString の使用は制限されていますが、将来的にはより適切に採用されることが期待されます。

この情報に基づいて、SecureString のコンストラクターは文字列を取得して char 配列にスライスするだけではいけません。

追加情報:

  • .NET Security ブログからの投稿で、ここで取り上げたものとほとんど同じことを説明しています。
  • もう1 つ はそれを再検討し、SecureString の内容をダンプできるツールについて言及しています。

編集:多くの情報に良い情報があるため、最良の回答を選ぶのは難しいと思いました。残念ながら、支援された回答オプションはありません。

于 2008-09-27T11:48:56.850 に答える
20

簡潔な答え

なぜ私はただ言うことができないのですか:

SecureString password = new SecureString("password");

今、あなたはpassword記憶にあるからです。それを消去する方法はありません-これはまさにSecureStringのポイントです。

長い答え

SecureStringが存在する理由は、使い終わった機密データを消去するためにZeroMemoryを使用できないためです。CLRが原因で発生する問題を解決するために存在します。

通常のネイティブアプリケーションでは、次のように呼び出しますSecureZeroMemory

メモリのブロックをゼロで埋めます。

: SecureZeroMemory は と同じですがZeroMemoryコンパイラはそれを最適化しません。

問題は、.NET 内で呼び出しできないことです。また、.NET では文字列は不変です。他の言語でできるように、文字列の内容を上書きすることさえできません。ZeroMemorySecureZeroMemory

//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.SecurePassword プロパティ

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を使用しません。

于 2016-12-16T21:17:41.370 に答える
15

現在のバージョンのフレームワークで SecureString を適切に使用できるシナリオはほとんどありません。これは、アンマネージ API と対話する場合にのみ役立ちます。Marshal.SecureStringToGlobalAllocUnicode を使用してマーシャリングできます。

System.String との間で変換するとすぐに、その目的が無効になります。

MSDNサンプルは、コンソール入力から一度に 1 文字ずつ SecureString を生成し、セキュリティで保護された文字列をアンマネージ API に渡します。かなり複雑で非現実的です。

.NET の将来のバージョンでは、SecureString のサポートが強化され、より便利になると予想される場合があります。たとえば、次のようになります。

  • SecureString Console.ReadLineSecure() などを使用して、コンソール入力を SecureString に読み取り、サンプルの複雑なコードをすべて使用する必要はありません。

  • パスワードを安全に入力できるように、TextBox.Text プロパティを安全な文字列として保存する WinForms TextBox の代替品。

  • パスワードを SecureString として渡すことを可能にするセキュリティ関連 API の拡張。

上記がなければ、SecureString の価値は限られます。

于 2008-09-26T19:02:03.043 に答える
12

1つのフラットなインスタンス化の代わりに文字の追加を行う必要がある理由は、バックグラウンドでSecureStringのコンストラクターに「password」を渡すと、その「password」文字列がメモリに配置され、セキュア文字列の目的が損なわれるためだと思います。

追加することにより、一度に1つの文字をメモリに入れるだけであり、物理的に隣接していないため、元の文字列を再構築するのがはるかに困難になります。私はここで間違っている可能性がありますが、それが私に説明された方法です。

このクラスの目的は、メモリダンプまたは同様のツールを介して安全なデータが公開されるのを防ぐことです。

于 2008-09-26T18:47:52.063 に答える
11

MSは、サーバー(デスクトップなど)をクラッシュさせる特定のインスタンスで、ランタイム環境がメモリダンプを実行して、メモリ内にあるものの内容を公開する場合があることを発見しました。Secure Stringは、攻撃者が文字列の内容を取得できないように、メモリ内で暗号化します。

于 2008-09-26T18:49:13.977 に答える
5

One of the big benefits of a SecureString is that it is supposed avoid the possibility of your data being stored to disk due to page caching. If you have a password in memory and then load a large program or data set, your password may get written to the swap file as your program is paged out of memory. With a SecureString, at least the data will not be sitting around indefinitely on your disk in clear text.

于 2008-09-26T18:55:32.217 に答える
4

説明にあるように、値は暗号化されて保存されます。つまり、プロセスのメモリダンプでは、文字列の値が明らかになりません(かなり深刻な作業が必要です)。

定数文字列からSecureStringを作成できない理由、暗号化されていないバージョンの文字列がメモリにあるためです。文字列を分割して作成するように制限すると、文字列全体が一度にメモリに保存されるリスクが軽減されます。

于 2008-09-26T18:51:33.693 に答える
4

SecureString の使用をやめます。PG 関係者はサポートを中止しているようです。将来的にプルする可能性もあります - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring

.NET Core のすべてのプラットフォームで SecureString から暗号化を削除する必要があります - SecureString を廃止する必要があります - おそらく .NET Core で SecureString を公開すべきではありません

于 2016-07-21T00:12:10.863 に答える
4

文字列が安全であるように意図されているためだと思います。つまり、ハッカーはそれを読み取ることができないはずです。文字列で初期化すると、ハッカーは元の文字列を読み取ることができます。

于 2008-09-26T18:46:09.930 に答える