1. ホーム
  2. c#

[解決済み】C#アプリケーションでSecureStringが実用化されることはありますか?

2022-04-03 18:35:16

質問

もし私の前提が間違っていたら、遠慮なく訂正してください。

MSDNから引用すると SecureString :

<ブロッククオート

機密を保持すべきテキストを表します。使用中はプライバシー保護のため暗号化され、不要になるとコンピュータのメモリから削除されます。

これはわかる、パスワードなどの個人情報を SecureString の上に System.String は、実際にメモリに格納される方法とタイミングを制御できるからです。 System.String :

<ブロッククオート

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

しかし、GUIアプリケーション(例えば、sshクライアント)の場合は SecureString からビルドする必要があります。 System.String . すべてのテキストコントロール は、その基礎となるデータ型として文字列を使用します。 .

つまり、ユーザーがキーを押すたびに、そこにあった古い文字列は破棄され、パスワードマスクを使用していても、テキストボックス内の値が何であるかを表す新しい文字列が構築されるということです。 そして、これらの値がいつメモリから破棄されるかを制御することはできません。 .

さて、いよいよサーバーにログインしてみましょう。何だと思います? 認証のために、接続に文字列を渡す必要があります。 . そこで SecureStringSystem.String ......そして今、ヒープ上に文字列があり、それを強制的にガベージコレクションにかける(あるいはバッファに0を書き込む)方法はない。

私が言いたいのは : 何をやっても、どこかで、その SecureString 行く に変換されます。 System.String つまり、少なくともヒープ上に存在することになります(ガベージコレクションの保証はありませんが)。

私が言いたいのは ssh接続に文字列を送るのを回避する方法や、コントロールに文字列を保存させる(カスタムコントロールを作る)方法はないでしょうか。この質問については、"ssh接続"を"ログインフォーム"、"登録フォーム"、"支払いフォーム"、"フード-あなたの子犬に食べさせるがあなたの子供ではないフォーム"などに置き換えられると思われます。

  • では、どの時点で SecureString になります。 実用的ですか?
  • を完全に根絶するために、余分な開発時間を費やす価値はあるのだろうか? を使用することはできません。 System.String オブジェクトを作成できますか?
  • の要点は何ですか? SecureString の時間を単純に短くすることです。 System.String がヒープ上にあるかどうか(物理的なスワップファイルに移動するリスクを減らす)?
  • もし、攻撃者がすでにヒープを検査する手段を持っているとしたら、ほとんどの場合、(A)すでにキーストロークを読み取る手段を持っているか、(B)すでに 物理的にマシンを持っている ... ということは SecureString どうせデータにアクセスできないのでしょう?
  • これは、単なる「曖昧さによるセキュリティ」なのでしょうか?

好奇心で質問攻めにしていたらごめんなさい。私の質問に自由に答えてください(あるいは私の仮定が完全に間違っていると言ってください)。

どのように解決するのですか?

には、実はとても実用的な使い方があります。 SecureString .

このようなシナリオを何度見たかご存知でしょうか。(答えは、「たくさん!」です)。

  • ログファイルに誤ってパスワードが表示される。
  • あるGUIで実行中のアプリケーションのコマンドラインが表示され、そのコマンドラインがパスワードで構成されていたことがあります。 おっと .
  • メモリプロファイラを使って、同僚とソフトウェアのプロファイリングをする。同僚があなたのパスワードをメモリ上で見る。非現実的に聞こえる?そんなことはありません。
  • を使ったことがあります。 RedGate 例外発生時にローカル変数の値をキャプチャできるソフトウェアがあり、驚くほど便利でした。でも、文字列のパスワードを誤って記録してしまうことは想像に難くない。
  • 文字列パスワードを含むクラッシュダンプです。

これらの問題を回避する方法をご存知ですか? SecureString . それは一般的に、そのような愚かな間違いをしないようにすることです。どのように回避するのでしょうか?パスワードは管理されていないメモリに暗号化され、本当の値には、自分が何をしているのか90%確信があるときだけアクセスできるようにすることで、それを回避しているのです。

という意味で。 SecureString はかなり簡単に動作します。

1) すべてが暗号化される

2) ユーザーの呼び出し AppendChar

3) UNMANAGED MEMORYのすべてを復号化し、文字を追加する。

4) UNMANAGED MEMORYで再度すべてを暗号化する。

もし、そのユーザーがあなたのコンピュータにアクセスできたら?ウイルスに感染すれば、すべての SecureStrings ? はい。必要なのは、自分自身を RtlEncryptMemory メモリが復号化されるときに、復号化されていないメモリアドレスの位置を取得し、それを読み出す。ほらね。実は、このようなウィルスを作れば、暗号化されていないメモリが使われていないか、常にスキャンすることができます。 SecureString で、そのアクティビティをすべて記録します。簡単な作業とは言いませんが、実現は可能です。このように、quot;powerfulness" の SecureString は、システム内にユーザーやウイルスが存在すると、完全に消えてしまいます。

あなたの投稿には、いくつかのポイントがあります。確かに、内部で文字列のパスワードを保持するUIコントロールの一部を使用する場合、実際の SecureString はそれほど有用ではありません。しかし、それでも、私が上に挙げたいくつかの愚かな行為から身を守ることができます。

また、他の方が指摘されているように、WPFはPasswordBoxをサポートしており、これは SecureString の内部で、その セキュアパスワード プロパティがあります。

要するに、機密データ(パスワード、クレジットカード、...)がある場合は SecureString . これは、C# Frameworkが踏襲しているものです。例えば NetworkCredential クラスは、パスワードを SecureString . もし、あなたが これ の.NETフレームワークにおける80以上の異なる使用法を見ることができます。 SecureString .

を変換しなければならないケースは多々あります。 SecureString を文字列に変換する必要があるからです。

通常の問題はどちらかです。

  1. APIがGENERICである。センシティブなデータがあることを知らない。
  2. APIは機密データを扱っていることを知っていて、"string"を使っている - それは単なる悪い設計だ。

良い指摘をいただきました。 SecureString が変換され string ? このようなことが起こるのは、1つ目のポイントが原因です。例えば、APIはそれが機密データであることを知らない。個人的にそのようなことは見たことがない。SecureStringから文字列を取り出すのは、そう簡単なことではありません。

簡単でない理由は簡単です。 ご指摘の通り、SecureStringを文字列に変換させることは想定していません。GCが作動してしまうのです。もし自分がそうしているのを見たら、一歩下がって自問自答する必要があります。このようなことをするようであれば、一歩下がって自問自答する必要があります。

ひとつ、面白い事例を見た。すなわち、WinApi関数LogonUserはLPTSTRをパスワードとして受け取るので、この関数で SecureStringToGlobalAllocUnicode . この場合、基本的に暗号化されていないパスワードがアンマネージドメモリに存在することになります。このパスワードは管理されていないメモリに保存されるため、使い終わったらすぐに削除する必要があります。

// Marshal the SecureString to unmanaged memory.
IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
   //...snip...
}
finally 
{
   // Zero-out and free the unmanaged string reference.
   Marshal.ZeroFreeGlobalAllocUnicode(rawPassword);
}

を常に拡張することができます。 SecureString のような拡張メソッドで ToEncryptedString(__SERVER__PUBLIC_KEY) を与えるものである。 string のインスタンスです。 SecureString これは、サーバーの公開鍵で暗号化されています。そして、サーバーだけがそれを復号化することができます。問題は解決しました。ガベージコレクションは、元の文字列を見ることはありません。これはまさに PSRemotingCryptoHelper ( EncryptSecureStringCore(SecureString secureString) ).

そして、ほとんど関連することとして。 Mono SecureStringは全く暗号化されません。 . 実装がコメントアウトされているのは、...お待ちください。 "なぜかnunitテストが壊れる".It comes causing nunit test breakage" ということで、最後のポイントになります。

SecureString はどこでもサポートされているわけではありません。もしプラットフォーム/アーキテクチャが SecureString という例外が発生します。ドキュメントにサポートされているプラットフォームのリストがあります。