.NETでSecureStringが必要になるのはいつですか?


179

.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のどの側面が欠けていますか?


3
11年後、MS SecureStringは新しい開発を推奨しなくなりました:github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Matt Thomas

回答:


4

SecureStringの使用を停止します。PGの連中がサポートをやめているようだ。おそらくそれを将来的にプルすることさえ-https ://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring

.NET CoreのすべてのプラットフォームでSecureStringから暗号化を削除する必要があります-SecureStringを廃止する必要があります-.NET CoreでSecureStringを公開しないでください


1
リンクが死んでいるが、上で運ぶために表示されます。docs.microsoft.com/en-us/dotnet/api/... パス前方execpt「いけない利用資格」にいくつかの非常に弱い指導を... - github.com/dotnet/platform- compat / blob / master / docs / DE0001.md ..証明書の秘密鍵を保護するためにパスワードを使用しないでください!
felickz

1
11年後、この答えは「新しい」正しいものになりました。リンクは古くなっているようですが、MSからのガイダンスは次のとおりです。SecureStringは使用しないでください
Richard Morgan

109

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

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

他の人が言ったように、あなたがSecureString文字ごとに作成しなければならない理由は、そうしないことの最初の明らかな欠陥のためです:おそらくあなたはおそらく普通の文字列として秘密の値を持っているので、ポイントは何ですか?

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


2
私はProcessStartInfoのPasswordプロパティを見て、それを偶然見つけました。タイプに注意を払うことさえせずに、コンパイラーが私に吠えるまで、それを通常の文字列に設定しました。
リチャードモーガン

SecureStringはDPAPIに基づいているため、対称暗号化キーを見つけるのは簡単ではありません
。DPAPI

1
また、ストレージでの暗号化の代わりにはならないので、それほど問題ではありませんが、不変の管理された.NET文字列の回避策です。
AviD 2008

2
「おそらくあなたは秘密の値をプレーンな文字列としてすでに持っているので、何の意味があるのですか?」この質問に対する答えはありますか?長期間にわたってパスワードをメモリに保存しておくことを意図している場合、せいぜい「何もしないよりはまし」なソリューションであるように見えます。
xr280xr 2013

2
いくつかの簡単なコード例の使用についてはどうですか?いつどのように使用するかをよく理解できると思います。
コデア2015年

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では、内部文字配列の内容は暗号化されています。APIがないか、キー管理の問題があるため、.NETはすべての環境で暗号化をサポートしていません。

勧告

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

資格情報を処理する一般的なアプローチは、資格情報を回避し、代わりに、証明書やWindows認証などの他の認証手段に依存することです。

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

素晴らしい答えがたくさん。これが議論されたものの簡単な概要です。

マイクロソフトは、機密情報(クレジットカード、パスワードなど)を使用してセキュリティを強化するために、SecureStringクラスを実装しました。それは自動的に提供します:

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

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

この情報に基づいて、SecureStringのコンストラクターは文字列を取得してchar配列にスライスするだけではなく、文字列をスペルアウトするとSecureStringの目的に反するためです。

追加情報:

  • ポスト .NETセキュリティからは、ここではカバーさとほぼ同じの話ブログ。
  • そして、もう1つは それを再検討し、SecureStringの内容をダンプできるツールに言及しています。

編集:たくさんの良い情報があるので、最良の答えを選ぶのは難しいと思いました。残念ながら、回答の選択肢はありません。


19

短い答え

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

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は、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.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に文字列を取得できますか?さて、あなたがしなければならないことは、そもそもStringにパスワードを持たせることをやめることです。あなたはそれを別のものに入れる必要がありました。でも、Char[]配列は参考になります。

これは、各文字追加して、完了時にプレーンテキストワイプできる場合です。

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

あなたはに保存されたパスワード必要いくつかのあなたは拭くことができるという記憶を。そこからSecureStringにロードします。


tl; dr:ZeroStringと同等の機能を提供するSecureStringが存在します。

一部の人々は、デバイスがロックされているときにメモリからユーザーのパスワードをワイプしたり、認証後にキーストロークをメモリからワイプしたりするポイントを理解しません。それらの人々はSecureStringを使用しません。


14

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

System.Stringとの間で変換を行うとすぐに、その目的は無効になります。

MSDN サンプルは、コンソール入力から一度にSecureStringの文字を生成し、安全な文字列をアンマネージAPIに渡します。かなり複雑で非現実的です。

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

  • SecureString Console.ReadLineSecure()または同様のコードで、サンプルのすべての複雑なコードを使わずに、SecureStringにコンソール入力を読み取ります。

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

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

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


12

フラットなインスタンス化の代わりに文字を追加する必要がある理由は、バックグラウンドでSecureStringのコンストラクターに「パスワード」を渡すと、その「パスワード」文字列がメモリに配置され、セキュリティで保護された文字列の目的が無効になるためです。

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

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


11

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


5

SecureStringの大きな利点の1つは、ページキャッシュが原因でデータがディスクに保存される可能性を回避することが想定されていることです。メモリにパスワードがあり、大きなプログラムまたはデータセットをロードした場合、プログラムがメモリからページアウトされると、パスワードがスワップファイルに書き込まれる可能性があります。SecureStringを使用すると、少なくともデータがクリアテキストでディスク上に無期限に残ることはありません。


4

これは、文字列が安全であることを意図しているためだと思います。つまり、ハッカーは文字列を読み取ることができません。文字列で初期化すると、ハッカーは元の文字列を読み取る可能性があります。


4

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

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


2
それらが定数文字列から構成を制限している場合、行foreach( "password" .ToCharArray()のchar c)はそれを無効にしますか?pass.AppendChar( 'p');である必要があります。pass.AppendChar( 'a'); etc?
Richard Morgan

はい、SecureStringが提供するほとんどの保護を簡単に破棄できます。彼らは足元を完全に撃ち落とすのを困難にしようとしている。明らかに、SecureStringに値を出し入れするための方法が必要です。そうしないと、何にも使用できません。
マークベッシー

1

もう1つの使用例は、支払いアプリケーション(POS)を使用していて、慎重な開発者であるため、機密データを格納するために不変データ構造使用できない場合です。たとえば、機密性の高いカードデータや認証メタデータを不変文字列に保存する場合、このデータが破棄された後、かなりの時間メモリで利用できる場合が常にあります。単純に上書きすることはできません。そのような機密データが暗号化されてメモリに保持される別の大きな利点。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.