SecureStringをSystem.Stringに変換する方法は?


156

それ以外に System.Stringを作成してSecureStringのセキュリティを解除することに関するすべての予約は、どうすれば実行できますか?

通常のSystem.Security.SecureStringをSystem.Stringに変換するにはどうすればよいですか?

SecureStringに精通している多くの方は、SecureStringを通常の.NET文字列に変換しないでください。これにより、すべてのセキュリティ保護が削除されるためです。 私が知っています。しかし、今のところ、私のプログラムはとにかく通常の文字列ですべてを行います。私はそのセキュリティを強化しようとしています。私にSecureStringを返すAPIを使用するつもりはありませんが、

Marshal.SecureStringToBSTRは知っていますが、そのBSTRを取得してSystem.Stringを作成する方法がわかりません。

なぜ私がこれをしたいのかを知りたいと思っている人のために、ユーザーからパスワードを取得し、それをHTMLフォームPOSTとして送信して、ユーザーをWebサイトにログインさせます。したがって、これは実際には、管理された暗号化されていないバッファーで行う必要があります。管理されていない、暗号化されていないバッファにアクセスできたとしても、ネットワークストリームにバイト単位のストリーム書き込みを行うことができ、それによってパスワードが安全に保たれることを願っています。これらのシナリオの少なくとも1つに対する回答を期待しています。

回答:


192

System.Runtime.InteropServices.Marshalクラスを使用します。

String SecureStringToString(SecureString value) {
  IntPtr valuePtr = IntPtr.Zero;
  try {
    valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
    return Marshal.PtrToStringUni(valuePtr);
  } finally {
    Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
  }
}

マネージ文字列オブジェクトの作成を避けたい場合は、次を使用して生データにアクセスできますMarshal.ReadInt16(IntPtr, Int32)

void HandleSecureString(SecureString value) {
  IntPtr valuePtr = IntPtr.Zero;
  try {
    valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
    for (int i=0; i < value.Length; i++) {
      short unicodeChar = Marshal.ReadInt16(valuePtr, i*2);
      // handle unicodeChar
    }
  } finally {
    Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
  }
}

1
数年後も賛成票を獲得しました。助けてくれてありがとう!簡単に言うと、これは静的メモリとしても機能します。
ジョンスーツ

使用してStopWatchSecureStringToString実行に4.6秒かかりました。それは私にとって遅くなることです。誰かが同じ時間または何かより速く得ますか?
radbyx

@radbyx迅速で汚れたテストセットアップでは、76ミリ秒で1000回呼び出すことができます。最初の呼び出しには0.3ミリ秒、その後の呼び出しには約0.07ミリ秒かかります。安全な文字列の大きさと、使用しているフレームワークのバージョンはどれですか。
Rasmus Faber

secureStringの長さは168です。質問に回答した場合、.NET Framework 3.5を使用していますか?私は5〜10回試しましたが、常に4.5〜4.65秒です。時間を
確保し

@RasmusFaber私の悪いDatabase.GetConnectionString()ことに、secureStringを取得するためにコードにを追加しました。これは、約5秒かかった邪悪な部分でした(そして、はい、私はそれを調べる必要があります!:)ストップウォッチでコードが.00ミリ秒かかったので、すべて良い。私を正しい方向に向けてくれてありがとう。
radbyx

108

明らかに、これがSecureStringの目的全体を打ち負かす方法を知っていますが、私はとにかく言い直します。

ワンライナーが必要な場合は、これを試してください:(.NET 4以降のみ)

string password = new System.Net.NetworkCredential(string.Empty, securePassword).Password;

ここで、securePasswordはSecureStringです。


10
本番環境では目的を達成できませんが、ソリューションは単体テストに最適です。ありがとう。
beterthanlife 2014

これは、SecureString(System.Security.SecureString)が私のApiController(webapi)に渡されていないことを理解するのに役立ちました。Thx
granadaCoder

5
PowerShellでこれに注意してください[System.Net.NetworkCredential]::new('', $securePassword).Password
stijn

1
@ TheIncorrigible1詳しく説明できますか?例えばときである''と同じ型ではありませんか[String]::Empty?またNew-Object Net.Credential、私にとっては機能しません:タイプ[Net.Credential]が見つかり
stijn

2
SecureStringの内容の暗号化されていないコピーを通常の文字列に作成するため、SecureStringの目的に反します。これを行うたびに、暗号化されていない文字列の少なくとも1つのコピー(およびガベージコレクションを使用して複数のコピー)をメモリに追加します。これは一部のセキュリティ上重要なアプリケーションのリスクと考えられており、そのリスクを軽減するためにSecureStringが特別に実装されました。
Steve In CO

49

ダン。 これを投稿した直後、私はこの記事の奥に答えを見つけました。ただし、このメソッドが公開するIntPtrの管理されていない、暗号化されていないバッファーに一度に1バイトずつアクセスできる方法を知っている場合は、セキュリティを維持するためにそこからマネージ文字列オブジェクトを作成する必要はありません。答えを追加してください。:)

static String SecureStringToString(SecureString value)
{
    IntPtr bstr = Marshal.SecureStringToBSTR(value);

    try
    {
        return Marshal.PtrToStringBSTR(bstr);
    }
    finally
    {
        Marshal.FreeBSTR(bstr);
    }
}

あなたは確かにunsafeキーワードとを使うことができますchar*、ただ呼び出すだけbstr.ToPointer()でキャストできます。
Ben Voigt 2016年

@BenVoigt BSTRでは、安全のために文字列データの後にnullターミネータがありますが、文字列にnull文字を埋め込むこともできます。したがって、それよりも少し複雑です。そのポインタの前にある長さのプレフィックスも取得する必要があります。docs.microsoft.com/en-us/previous-versions/windows/desktop/...
ヴィム・クーネン

@WimCoenen:真実だが重要ではない。BSTRに格納される長さは、からすでに利用可能な長さのコピーになりますSecureString.Length
Ben Voigt

@BenVoigtああ、私の悪い。SecureStringは文字列に関する情報を公開していないと思いました。
Wim Coenen

@WimCoenen:SecureString値を非表示にするのではなく、ガベージコレクションされたメモリ、ページファイルなど、確実に上書きできない領域に値のコピーが作成されないようにします。SecureStringライフタイムが終了すると、絶対に秘密のコピーはメモリに残りません。コピーの作成とリークを防ぐことはできませんが、決して防ぐことはありません。
Ben Voigt

15

私の意見では、拡張メソッドはこれを解決する最も快適な方法です。

私が取った スティーブをCOの 優れた答えに取り入れ、次のように拡張クラスに入れました。また、反対方向(文字列->セキュア文字列)をサポートするために追加した2番目のメソッドも一緒に追加しました。これにより、セキュア文字列を作成して変換できますその後の通常の文字列:

public static class Extensions
{
    // convert a secure string into a normal plain text string
    public static String ToPlainString(this System.Security.SecureString secureStr)
    {
        String plainStr=new System.Net.NetworkCredential(string.Empty, secureStr).Password;
        return plainStr;
    }

    // convert a plain text string into a secure string
    public static System.Security.SecureString ToSecureString(this String plainStr)
    {
        var secStr = new System.Security.SecureString(); secStr.Clear();
        foreach (char c in plainStr.ToCharArray())
        {
            secStr.AppendChar(c);
        }
        return secStr;
    }
}

これで、今できます 、文字列を次のように簡単に変換ます

// create a secure string
System.Security.SecureString securePassword = "MyCleverPwd123".ToSecureString(); 
// convert it back to plain text
String plainPassword = securePassword.ToPlainString();  // convert back to normal string

ただし、デコード方法はテストにのみ使用してください。


14

SecureString依存する関数がカプセル化するのが最善だと思いますメモリ内の復号化された文字列をより適切に制御するために、が依存ロジックを匿名関数ます(ピン留め後)。

このスニペットでSecureStringsを復号化するための実装は、次のようになります。

  1. 文字列をメモリに固定します(これはあなたがやりたいことですが、ここでほとんどの回答から欠落しているように見えます)。
  2. その参照をFunc / Actionデリゲートに渡します。
  3. メモリからスクラブして、finallyブロック内のGCを解放します。

これにより、呼び出し側を「標準化」して維持するのが明らかに容易になります。

  • string DecryptSecureString(...)ヘルパー関数から復号化された文字列を返します。
  • 必要なときにこのコードを複製する。

ここで、2つのオプションがあることに注意してください。

  1. static T DecryptSecureString<T>これによりFunc、呼び出し元からデリゲートの結果にアクセスできます(DecryptSecureStringWithFuncテストメソッドに示されています)。
  2. static void DecryptSecureStringActionDecryptSecureStringWithActionテストメソッドで示されているように)実際には何も返したくない、または返す必要がない場合にデリゲートを使用する「void」バージョンです。

両方の使用例は、StringsTest含まれているクラスにあります。

Strings.cs

using System;
using System.Runtime.InteropServices;
using System.Security;

namespace SecurityUtils
{
    public partial class Strings
    {
        /// <summary>
        /// Passes decrypted password String pinned in memory to Func delegate scrubbed on return.
        /// </summary>
        /// <typeparam name="T">Generic type returned by Func delegate</typeparam>
        /// <param name="action">Func delegate which will receive the decrypted password pinned in memory as a String object</param>
        /// <returns>Result of Func delegate</returns>
        public static T DecryptSecureString<T>(SecureString secureString, Func<string, T> action)
        {
            var insecureStringPointer = IntPtr.Zero;
            var insecureString = String.Empty;
            var gcHandler = GCHandle.Alloc(insecureString, GCHandleType.Pinned);

            try
            {
                insecureStringPointer = Marshal.SecureStringToGlobalAllocUnicode(secureString);
                insecureString = Marshal.PtrToStringUni(insecureStringPointer);

                return action(insecureString);
            }
            finally
            {
                //clear memory immediately - don't wait for garbage collector
                fixed(char* ptr = insecureString )
                {
                    for(int i = 0; i < insecureString.Length; i++)
                    {
                        ptr[i] = '\0';
                    }
                }

                insecureString = null;

                gcHandler.Free();
                Marshal.ZeroFreeGlobalAllocUnicode(insecureStringPointer);
            }
        }

        /// <summary>
        /// Runs DecryptSecureString with support for Action to leverage void return type
        /// </summary>
        /// <param name="secureString"></param>
        /// <param name="action"></param>
        public static void DecryptSecureString(SecureString secureString, Action<string> action)
        {
            DecryptSecureString<int>(secureString, (s) =>
            {
                action(s);
                return 0;
            });
        }
    }
}

StringsTest.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security;

namespace SecurityUtils.Test
{
    [TestClass]
    public class StringsTest
    {
        [TestMethod]
        public void DecryptSecureStringWithFunc()
        {
            // Arrange
            var secureString = new SecureString();

            foreach (var c in "UserPassword123".ToCharArray())
                secureString.AppendChar(c);

            secureString.MakeReadOnly();

            // Act
            var result = Strings.DecryptSecureString<bool>(secureString, (password) =>
            {
                return password.Equals("UserPassword123");
            });

            // Assert
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void DecryptSecureStringWithAction()
        {
            // Arrange
            var secureString = new SecureString();

            foreach (var c in "UserPassword123".ToCharArray())
                secureString.AppendChar(c);

            secureString.MakeReadOnly();

            // Act
            var result = false;

            Strings.DecryptSecureString(secureString, (password) =>
            {
                result = password.Equals("UserPassword123");
            });

            // Assert
            Assert.IsTrue(result);
        }
    }
}

明らかに、これは次の方法でこの関数の悪用を防止しないので、これを行わないように注意してください:

[TestMethod]
public void DecryptSecureStringWithAction()
{
    // Arrange
    var secureString = new SecureString();

    foreach (var c in "UserPassword123".ToCharArray())
        secureString.AppendChar(c);

    secureString.MakeReadOnly();

    // Act
    string copyPassword = null;

    Strings.DecryptSecureString(secureString, (password) =>
    {
        copyPassword = password; // Please don't do this!
    });

    // Assert
    Assert.IsNull(copyPassword); // Fails
}

幸せなコーディング!


セクションのMarshal.Copy(new byte[insecureString.Length], 0, insecureStringPointer, (int)insecureString.Length);代わりに使用しないのはなぜfixedですか?
sclarke81

@ sclarke81、良いアイデアですが[char]、ではなくを使用する必要があります[byte]
mklement0

1
全体的なアプローチが有望であるが、私は安全でない(プレーンテキスト)のコピーを含む管理対象の文字列を固定であなたの試みが有効であるとは思わない:何を代わりにピン留めしていることで、元のあなたが初期化されてきたことを文字列オブジェクトString.Empty、によって作成および返された、新しく割り当てられたインスタンスではありませんMarshal.PtrToStringUni()
mklement0

7

rdev5から回答に基づいて、次の拡張メソッドを作成しました。マネージ文字列を固定することは、ガベージコレクターが文字列を移動したり、消去できないコピーを残したりするのを防ぐため、重要です。

私のソリューションの利点は、安全でないコードが必要ないことです。

/// <summary>
/// Allows a decrypted secure string to be used whilst minimising the exposure of the
/// unencrypted string.
/// </summary>
/// <typeparam name="T">Generic type returned by Func delegate.</typeparam>
/// <param name="secureString">The string to decrypt.</param>
/// <param name="action">
/// Func delegate which will receive the decrypted password as a string object
/// </param>
/// <returns>Result of Func delegate</returns>
/// <remarks>
/// This method creates an empty managed string and pins it so that the garbage collector
/// cannot move it around and create copies. An unmanaged copy of the the secure string is
/// then created and copied into the managed string. The action is then called using the
/// managed string. Both the managed and unmanaged strings are then zeroed to erase their
/// contents. The managed string is unpinned so that the garbage collector can resume normal
/// behaviour and the unmanaged string is freed.
/// </remarks>
public static T UseDecryptedSecureString<T>(this SecureString secureString, Func<string, T> action)
{
    int length = secureString.Length;
    IntPtr sourceStringPointer = IntPtr.Zero;

    // Create an empty string of the correct size and pin it so that the GC can't move it around.
    string insecureString = new string('\0', length);
    var insecureStringHandler = GCHandle.Alloc(insecureString, GCHandleType.Pinned);

    IntPtr insecureStringPointer = insecureStringHandler.AddrOfPinnedObject();

    try
    {
        // Create an unmanaged copy of the secure string.
        sourceStringPointer = Marshal.SecureStringToBSTR(secureString);

        // Use the pointers to copy from the unmanaged to managed string.
        for (int i = 0; i < secureString.Length; i++)
        {
            short unicodeChar = Marshal.ReadInt16(sourceStringPointer, i * 2);
            Marshal.WriteInt16(insecureStringPointer, i * 2, unicodeChar);
        }

        return action(insecureString);
    }
    finally
    {
        // Zero the managed string so that the string is erased. Then unpin it to allow the
        // GC to take over.
        Marshal.Copy(new byte[length], 0, insecureStringPointer, length);
        insecureStringHandler.Free();

        // Zero and free the unmanaged string.
        Marshal.ZeroFreeBSTR(sourceStringPointer);
    }
}

/// <summary>
/// Allows a decrypted secure string to be used whilst minimising the exposure of the
/// unencrypted string.
/// </summary>
/// <param name="secureString">The string to decrypt.</param>
/// <param name="action">
/// Func delegate which will receive the decrypted password as a string object
/// </param>
/// <returns>Result of Func delegate</returns>
/// <remarks>
/// This method creates an empty managed string and pins it so that the garbage collector
/// cannot move it around and create copies. An unmanaged copy of the the secure string is
/// then created and copied into the managed string. The action is then called using the
/// managed string. Both the managed and unmanaged strings are then zeroed to erase their
/// contents. The managed string is unpinned so that the garbage collector can resume normal
/// behaviour and the unmanaged string is freed.
/// </remarks>
public static void UseDecryptedSecureString(this SecureString secureString, Action<string> action)
{
    UseDecryptedSecureString(secureString, (s) =>
    {
        action(s);
        return 0;
    });
}

コードは文字列のコピーをリークしませんが、それでも絶望の落とし穴を表しています。System.Stringオブジェクトのほぼすべての操作で、固定されていないコピーと消去されていないコピーが作成されます。これがに組み込まれていない理由SecureStringです。
Ben Voigt

文字列全体をゼロにするには、使用する必要がありますnew char[length](またはで乗算lengthしますsizeof(char))。
mklement0

@BenVoigt:actionデリゲートが一時的、固定され、次にゼロ化された文字列のコピーを作成しない限り、このアプローチはSecureStringそれ自体と同じか安全ではないはずです。後者を使用するには、プレーンテキスト表現も必要です安全な文字列はOSレベルの構造ではないため、ある時点で作成されます。相対的なセキュリティは、その文字列の寿命を制御し、使用後に文字列が確実に消去されるようにすることから来ています。
mklement0

@ mklement0:SecureString場所全体にコピーを作成するメンバー関数とオーバーロードされた演算子がありません。 System.Stringします。
Ben Voigt

1
@ mklement0:をNetworkCredential受け入れるコンストラクタに渡すことを考えると、これはかなり馬鹿げていSecureStringます。
Ben Voigt

0

このC#コードは必要なものです。

%ProjectPath%/SecureStringsEasy.cs

using System;
using System.Security;
using System.Runtime.InteropServices;
namespace SecureStringsEasy
{
    public static class MyExtensions
    {
        public static SecureString ToSecureString(string input)
        {
            SecureString secureString = new SecureString();
            foreach (var item in input)
            {
                secureString.AppendChar(item);
            }
            return secureString;
        }
        public static string ToNormalString(SecureString input)
        {
            IntPtr strptr = Marshal.SecureStringToBSTR(input);
            string normal = Marshal.PtrToStringBSTR(strptr);
            Marshal.ZeroFreeBSTR(strptr);
            return normal;
        }
    }
}

0

私はsclarke81によるこの答えから導きました。私は彼の答えが好きで、私は派生物を使っていますが、sclarke81にはバグがあります。評判がないのでコメントできない。問題は、別の答えを保証するほどではなく、編集できるほど小さいようです。だから私はしました。拒否されました。だから今、私たちは別の答えを持っています。

sclarke81(最終的に)これが表示されることを願っています。

Marshal.Copy(new byte[length], 0, insecureStringPointer, length);

でなければなりません:

Marshal.Copy(new byte[length * 2], 0, insecureStringPointer, length * 2);

そしてバグ修正を含む完全な答え:


    /// 
    /// Allows a decrypted secure string to be used whilst minimising the exposure of the
    /// unencrypted string.
    /// 
    /// Generic type returned by Func delegate.
    /// The string to decrypt.
    /// 
    /// Func delegate which will receive the decrypted password as a string object
    /// 
    /// Result of Func delegate
    /// 
    /// This method creates an empty managed string and pins it so that the garbage collector
    /// cannot move it around and create copies. An unmanaged copy of the the secure string is
    /// then created and copied into the managed string. The action is then called using the
    /// managed string. Both the managed and unmanaged strings are then zeroed to erase their
    /// contents. The managed string is unpinned so that the garbage collector can resume normal
    /// behaviour and the unmanaged string is freed.
    /// 
    public static T UseDecryptedSecureString(this SecureString secureString, Func action)
    {
        int length = secureString.Length;
        IntPtr sourceStringPointer = IntPtr.Zero;

        // Create an empty string of the correct size and pin it so that the GC can't move it around.
        string insecureString = new string('\0', length);
        var insecureStringHandler = GCHandle.Alloc(insecureString, GCHandleType.Pinned);

        IntPtr insecureStringPointer = insecureStringHandler.AddrOfPinnedObject();

        try
        {
            // Create an unmanaged copy of the secure string.
            sourceStringPointer = Marshal.SecureStringToBSTR(secureString);

            // Use the pointers to copy from the unmanaged to managed string.
            for (int i = 0; i < secureString.Length; i++)
            {
                short unicodeChar = Marshal.ReadInt16(sourceStringPointer, i * 2);
                Marshal.WriteInt16(insecureStringPointer, i * 2, unicodeChar);
            }

            return action(insecureString);
        }
        finally
        {
            // Zero the managed string so that the string is erased. Then unpin it to allow the
            // GC to take over.
            Marshal.Copy(new byte[length * 2], 0, insecureStringPointer, length * 2);
            insecureStringHandler.Free();

            // Zero and free the unmanaged string.
            Marshal.ZeroFreeBSTR(sourceStringPointer);
        }
    }

    /// 
    /// Allows a decrypted secure string to be used whilst minimising the exposure of the
    /// unencrypted string.
    /// 
    /// The string to decrypt.
    /// 
    /// Func delegate which will receive the decrypted password as a string object
    /// 
    /// Result of Func delegate
    /// 
    /// This method creates an empty managed string and pins it so that the garbage collector
    /// cannot move it around and create copies. An unmanaged copy of the the secure string is
    /// then created and copied into the managed string. The action is then called using the
    /// managed string. Both the managed and unmanaged strings are then zeroed to erase their
    /// contents. The managed string is unpinned so that the garbage collector can resume normal
    /// behaviour and the unmanaged string is freed.
    /// 
    public static void UseDecryptedSecureString(this SecureString secureString, Action action)
    {
        UseDecryptedSecureString(secureString, (s) =>
        {
            action(s);
            return 0;
        });
    }
}

いい視点ね; 参照された回答にコメントを残しました。OPに通知する必要があります。
mklement0

0

sclarke81ソリューションとJohn Flaherty修正による最終的な作業ソリューションは次のとおりです。

    public static class Utils
    {
        /// <remarks>
        /// This method creates an empty managed string and pins it so that the garbage collector
        /// cannot move it around and create copies. An unmanaged copy of the the secure string is
        /// then created and copied into the managed string. The action is then called using the
        /// managed string. Both the managed and unmanaged strings are then zeroed to erase their
        /// contents. The managed string is unpinned so that the garbage collector can resume normal
        /// behaviour and the unmanaged string is freed.
        /// </remarks>
        public static T UseDecryptedSecureString<T>(this SecureString secureString, Func<string, T> action)
        {
            int length = secureString.Length;
            IntPtr sourceStringPointer = IntPtr.Zero;

            // Create an empty string of the correct size and pin it so that the GC can't move it around.
            string insecureString = new string('\0', length);
            var insecureStringHandler = GCHandle.Alloc(insecureString, GCHandleType.Pinned);

            IntPtr insecureStringPointer = insecureStringHandler.AddrOfPinnedObject();

            try
            {
                // Create an unmanaged copy of the secure string.
                sourceStringPointer = Marshal.SecureStringToBSTR(secureString);

                // Use the pointers to copy from the unmanaged to managed string.
                for (int i = 0; i < secureString.Length; i++)
                {
                    short unicodeChar = Marshal.ReadInt16(sourceStringPointer, i * 2);
                    Marshal.WriteInt16(insecureStringPointer, i * 2, unicodeChar);
                }

                return action(insecureString);
            }
            finally
            {
                // Zero the managed string so that the string is erased. Then unpin it to allow the
                // GC to take over.
                Marshal.Copy(new byte[length * 2], 0, insecureStringPointer, length * 2);
                insecureStringHandler.Free();

                // Zero and free the unmanaged string.
                Marshal.ZeroFreeBSTR(sourceStringPointer);
            }
        }

        /// <summary>
        /// Allows a decrypted secure string to be used whilst minimising the exposure of the
        /// unencrypted string.
        /// </summary>
        /// <param name="secureString">The string to decrypt.</param>
        /// <param name="action">
        /// Func delegate which will receive the decrypted password as a string object
        /// </param>
        /// <returns>Result of Func delegate</returns>
        /// <remarks>
        /// This method creates an empty managed string and pins it so that the garbage collector
        /// cannot move it around and create copies. An unmanaged copy of the the secure string is
        /// then created and copied into the managed string. The action is then called using the
        /// managed string. Both the managed and unmanaged strings are then zeroed to erase their
        /// contents. The managed string is unpinned so that the garbage collector can resume normal
        /// behaviour and the unmanaged string is freed.
        /// </remarks>
        public static void UseDecryptedSecureString(this SecureString secureString, Action<string> action)
        {
            UseDecryptedSecureString(secureString, (s) =>
            {
                action(s);
                return 0;
            });
        }
    }

-5
// using so that Marshal doesn't have to be qualified
using System.Runtime.InteropServices;    
//using for SecureString
using System.Security;
public string DecodeSecureString (SecureString Convert) 
{
    //convert to IntPtr using Marshal
    IntPtr cvttmpst = Marshal.SecureStringToBSTR(Convert);
    //convert to string using Marshal
    string cvtPlainPassword = Marshal.PtrToStringAuto(cvttmpst);
    //return the now plain string
    return cvtPlainPassword;
}

この回答にはメモリリークがあります。
Ben Voigt

@BenVoigtこれがどのようにメモリリークを起こしているのか説明してください。
El Ronnoco

4
@ElRonnoco:BSTR明示的に解放されるものはなく、それは.NETオブジェクトではないため、ガベージコレクターもそれを処理しません。5年前に投稿され、リークしないstackoverflow.com/a/818709/103167と比較してください。
Ben Voigt 2016年

この回答は、Windows以外のプラットフォームでは機能しません。PtrToStringAutoは、説明のために間違っては以下を参照してくださいgithub.com/PowerShell/PowerShell/issues/...
K.フランク

-5

StringBuilder代わりにを使用すると、string完了時にメモリ内の実際の値を上書きできます。そうすれば、ガベージコレクションがパスワードを取得するまで、パスワードがメモリ内に滞留することはありません。

StringBuilder.Append(plainTextPassword);
StringBuilder.Clear();
// overwrite with reasonably random characters
StringBuilder.Append(New Guid().ToString());

2
これはtrueですが、ガベージコレクターは、世代の圧縮中にStringBuilderバッファーをメモリ内で移動する可能性があります。これにより、破棄されない残りのコピー(またはそれ以上)が残っているため、「実際の値の上書き」が失敗します。
Ben Voigt 2016年

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