将字符串转换为 SecureString

问题描述 投票:0回答:16

如何将

String
转换为
SecureString

c# .net security securestring
16个回答
259
投票

还有另一种方法可以在

SecureString
String
之间进行转换。

1。字符串到 SecureString

SecureString theSecureString = new NetworkCredential("", "myPass").SecurePassword;

2。安全字符串到字符串

string theString = new NetworkCredential("", theSecureString).Password;

这是链接


166
投票

你不知道。使用 SecureString 对象的全部原因是避免创建字符串对象(该对象被加载到内存中并以明文形式保存在那里,直到垃圾回收)。但是,您可以通过附加字符将字符添加到 SecureString。

var s = new SecureString();
s.AppendChar('d');
s.AppendChar('u');
s.AppendChar('m');
s.AppendChar('b');
s.AppendChar('p');
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('d');

81
投票

以下方法有助于将字符串转换为安全字符串

private SecureString ConvertToSecureString(string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    var securePassword = new SecureString();

    foreach (char c in password)
        securePassword.AppendChar(c);

    securePassword.MakeReadOnly();
    return securePassword;
}

25
投票

您可以按照以下步骤操作:

string password = "test";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();

18
投票

这是一个廉价的 linq 技巧。

            SecureString sec = new SecureString();
            string pwd = "abc123"; /* Not Secure! */
            pwd.ToCharArray().ToList().ForEach(sec.AppendChar);
            /* and now : seal the deal */
            sec.MakeReadOnly();

14
投票

我只是想向所有说“这不是

SecureString
”的人指出,许多提出这个问题的人可能在一个应用程序中,无论出于何种原因,无论合理与否,他们都是特别关心将密码的临时副本作为可 GC 的字符串放在堆上,但他们必须使用接受
SecureString
对象的 API。所以,你有一个应用程序,你不关心密码是否在堆上,也许它仅供内部使用,密码在那里只是因为底层网络协议需要它,你发现该字符串在哪里存储的密码不能用于例如设置一个远程 PowerShell 运行空间——但是没有简单、直接的一句话来创建您需要的SecureString。这是一个小小的不便——但可能是值得的,以确保真正需要
SecureString
的应用程序不会诱使作者使用 System.String
System.Char[]
中介。 :-)
    
我会把这个扔出去。为什么?


10
投票

我冒昧地说,在担心保护应用程序字符串之前,您可能需要处理一些设计级别的问题。请向我们提供更多有关您想要做什么的信息,我们也许能够提供更好的帮助。

unsafe { fixed(char* psz = password) return new SecureString(psz, password.Length); }


10
投票
没有花哨的 linq,没有手动添加所有字符,只是简单明了:

6
投票

我同意 Spence (+1),但如果您这样做是为了学习或测试目的,您可以在字符串中使用 foreach,使用 AppendChar 方法将每个字符附加到安全字符串。

4
投票

以下 2 个扩展应该可以解决问题:


4
投票

对于

char
    数组
  1. public static SecureString ToSecureString(this char[] _self) { SecureString knox = new SecureString(); foreach (char c in _self) { knox.AppendChar(c); } return knox; }

    
    

    还有
    string
  2. public static SecureString ToSecureString(this string _self) { SecureString knox = new SecureString(); char[] chars = _self.ToCharArray(); foreach (char c in chars) { knox.AppendChar(c); } return knox; }

    
    

    感谢
    John Dagg
AppendChar

推荐。

如果您想将 

string

3
投票
SecureString

的转换压缩为

LINQ
语句,您可以将其表达如下:

var plain = "The quick brown fox jumps over the lazy dog"; var secure = plain .ToCharArray() .Aggregate( new SecureString() , (s, c) => { s.AppendChar(c); return s; } , (s) => { s.MakeReadOnly(); return s; } );

但是,请记住,使用

LINQ
 不会提高此解决方案的安全性。它与从 
string

SecureString
的任何转换都存在同样的缺陷。只要原始
string
保留在内存中,数据就容易受到攻击。

话虽这么说,上面的语句可以提供的是将
SecureString
的创建、用数据初始化并最终锁定它以防止修改结合在一起。

为了完整起见,我添加了两个单元测试和方法,用于从 char 数组和字符串转换为 SecureString 并再次转换回来。您应该尝试完全避免字符串,只传递指向 char 数组的指针或 char 数组本身,就像我在这里提供的方法一样,因为字符串是不安全的,因为它们将纯文本数据保存在托管内存中,其数量相当不确定。直到下一次 GC 运行或强制执行之前,最好尽快将字符数组放入 SecureString 中并将其保留在那里,并再次将其作为字符数组读回。


1
投票

using NUnit.Framework; using System; using SecureStringExtensions; using System.Security; namespace SecureStringExtensions.Test { [TestFixture] public class SecureStringExtensionsTest { [Test] [TestCase(new char[] { 'G', 'O', 'A', 'T', '1', '2', '3' })] public void CopyCharArrayToSecureStringAndCopyBackToCharArrayReturnsExpected(char[] inputChars) { SecureString sec = inputChars.ToSecureString(); var copiedFromSec = sec.FromSecureStringToCharArray(); CollectionAssert.AreEqual(copiedFromSec, inputChars); } [Test] [TestCase("GOAT456")] public void CopyStringToSecureStringAndCopyBackToUnsafeStringReturnsExpected(string inputString) { SecureString sec = inputString.ToSecureString(); var copiedFromSec = sec.FromSecureStringToUnsafeString(); Assert.AreEqual(copiedFromSec, inputString); } } }

我们这里有扩展方法:

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

namespace SecureStringExtensions
{
    public static class SecureStringExtensions
    {
        public static SecureString ToSecureString(this string str)
        {
            return ToSecureString(str.ToCharArray());
        }

        public static SecureString ToSecureString(this char[] str)
        {
            var secureString = new SecureString();
            Array.ForEach(str, secureString.AppendChar);
            return secureString;
        }

        /// <summary>
        /// Creates a managed character array from the secure string using methods in System.Runetime.InteropServices
        /// copying data into a BSTR (unmanaged binary string) and then into a managed character array which is returned from this method.
        /// Data in the unmanaged memory temporarily used are freed up before the method returns.
        /// </summary>
        /// <param name="secureString"></param>
        /// <returns></returns>
        public static char[] FromSecureStringToCharArray(this SecureString secureString)
        {
            char[] bytes;
            var ptr = IntPtr.Zero;
            try
            {
                //alloc unmanaged binary string  (BSTR) and copy contents of SecureString into this BSTR
                ptr = Marshal.SecureStringToBSTR(secureString);
                bytes = new char[secureString.Length];
                //copy to managed memory char array from unmanaged memory 
                Marshal.Copy(ptr, bytes, 0, secureString.Length);
            }
            finally
            {
                if (ptr != IntPtr.Zero)
                {
                    //free unmanaged memory
                    Marshal.ZeroFreeBSTR(ptr);
                }
            }
            return bytes;
        }

        /// <summary>
        /// Returns an unsafe string in managed memory from SecureString. 
        /// The use of this method is not recommended - use instead the <see cref="FromSecureStringToCharArray(SecureString)"/> method
        /// as that method has not got multiple copies of data in managed memory like this method.
        /// Data in unmanaged memory temporarily used are freed up before the method returns.
        /// </summary>
        /// <param name="secureString"></param>
        /// <returns></returns>
        public static string FromSecureStringToUnsafeString(this SecureString secureString)
        {
            if (secureString == null)
            {
                throw new ArgumentNullException(nameof(secureString));
            }
            var unmanagedString = IntPtr.Zero;
            try
            {
                //copy secure string into unmanaged memory
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
                //alloc managed string and copy contents of unmanaged string data into it
                return Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                    if (unmanagedString != IntPtr.Zero)
                {
                    Marshal.FreeBSTR(unmanagedString);
                }
            }
        }

    }
}

在这里,我们使用 System.Runtime.InteropServices 中的方法临时分配 BSTR(二进制非托管字符串),并确保释放临时使用的非托管内存。


我发现令人惊奇的是我仍在学习,即使涉及到处理敏感字符串!


0
投票
https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

不要将 SecureString 用于新代码。将代码移植到 .NET Core 时,请考虑数组的内容在内存中未加密。 处理凭据的一般方法是避免它们,而是依赖其他方式进行身份验证,例如证书或 Windows 身份验证。

此外,保护敏感字符串的一种常见“真正安全”方法是在配置文件本身中对其进行加密,因为操作系统级别没有安全字符串概念。

public class PasswordSecurityManager { private string? _password=default; private int? _length=default; public void SetPassword(string pass) { _password = _password ?? pass; _length = _length.HasValue ? _length : pass.Length; } public SecureString GetPassword() { if (_password is null) throw new InvalidOperationException("No password is specified!"); unsafe { fixed(char* psz = _password) return new SecureString(psz, _length.Value); } } }


0
投票
您可以使用这个简单的脚本

-1
投票

© www.soinside.com 2019 - 2024. All rights reserved.