将字符串转换为SecureString


Answers:


137

你不知道 使用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');

13
“这种组合是12345……那是白痴在他的行李上所拥有的那种东西!”
Kolob Canyon

8
我所看到的是*****
Ian Boyd

AppendChar直到运行时才执行,所以那些字符仍然可以从IL中读取,对吗?也许一些编译时混淆也可能会有所帮助……也就是说,如果您正在硬编码密码。
samis

5
这是一个la脚的论点。您在哪里获得密码?从表单或命令行。在他们创建直接从设备或命令行参数读取安全字符串的方法之前,我们需要将字符串转换为SecureString。
Quarkly

1
@DonaldAirey,您从秘密管理员处获得密码。通常,我们在这里谈论的秘密不是用户密码,而是可能导致特权升级或数据泄漏的事情。这意味着密码是用于其他服务的,不应在命令行或通过网络通道的明文中传递。
巴里·凯利

159

还有一种在SecureString和之间进行转换的方法String

1.字符串到SecureString

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

2. SecureString转换为String

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

这是链接


3
到目前为止,这是最常见用例的最佳解决方案!
Dan Bechard

16
SecureString如果代码使用string想要保护的值创建对象,则使用a没有意义。其目的SecureString是避免在托管内存中使用字符串,因此攻击者检查该内存可以发现您要隐藏的值。由于NetworkCredential您要调用的构造函数需要一个字符串,所以这不是走的路...当然,您的代码是在SecureString之间来回转换的简便方法,但是使用它使您的代码与使用简单的代码一样安全string
Gian Paolo

14
@GianPaolo虽然在理论上是正确的,但实际上SecureString在处理某些库时我们仍然需要使用。坦白说,如果有人正在积极扫描应用程序的内存,那么您已经迷路了。即使您正确使用了SecureString(我从未见过),也将提取其他有价值的数据。
乔纳森·艾伦

1
@乔纳森·艾伦(JonathanAllen):您可能是对的,但这仅是因为我们有一种将安全视为事后想法的文化。如果您要创建食谱网站,朝鲜不太可能尝试扫描程序的内存。如果您正在编写银行软件,威胁就更加真实了。
Eric J.19年

58

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

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;
}

26
+1,但请注意,将密码作为字符串参数传入会在托管内存中创建未加密的字符串实例,并首先破坏了“ SecureString”的目的。只是为将来使用此代码的人指出这一点。
科迪

19
@Cody没错,这是一个好点,但是我们很多人都不在乎SecureString是否安全,而只是在使用它,因为某些Microsoft API要求使用它作为参数。
Dan Bechard

3
@Cody证明,即使是SecureString类也无法使字符串保持加密。这就是为什么MS正在考虑obsoleting类型github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
马丁·布朗

19

您可以遵循以下步骤:

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

11

这是一个便宜的linq技巧。

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

32
这个答案是一种练习,它正在查看一次可以生成多少个纯文本的临时副本
Mike Caron

1
因为@ john-dagg提出的想法是不要用密码设置字符串,因为如果这样做,使用安全字符串就没有任何好处了。在您以纯文本形式输入密码的情况下,以后再使用安全字符串将不会保护任何内容。我希望您理解securestring的目的是为了防止查看反汇编程序或调试器的人员使用您的字符串,因此请查看IL /内存中的内容。
user734028

8

我把它扔在那里。为什么?

您不能只是将所有字符串更改为安全字符串,而突然您的应用程序是“安全的”。安全字符串的设计目的是使字符串尽可能长时间地保持加密,并且仅在很短的时间内解密,并在对其执行操作后擦除内存。

我冒昧地说,在担心保护应用程序字符串之前,您可能需要处理一些设计级别的问题。向我们提供有关您的尝试操作的更多信息,我们可能会更好地提供帮助。


1
我只想用它为ProcessStartInfo设置密码并以其他用户身份运行我的exe。。这对我有用...
Developer404 2009年

4
通过在安全系统上运行我的应用程序,可以确保其安全。我不太关心这个特定的字符串在内存中被加密。该系统上还有更多重要的信息要担心,如果它们遭到破坏。我的程序需要利用Microsoft API来简单地要求SecureString。暗示开发人员考虑自己的用例,并确定将字符串转换为SecureString在上下文中是否是有效操作。
Dan Bechard

因此,如果某人使用DotPeek这样的反编译器,这种方法不会阻止他看到密码?在这种情况下,有没有办法隐藏字符串?
M.Parent '19

有几种方法,具体取决于您要克服的威胁。如果要保护用户信息免受本地管理员以外的任何人的侵害,则可以在Windows上使用DPAPI方法对文件进行加密并将其存储在其中,然后将其读取为安全字符串,然后将其丢弃。如果是公司机密,那么简短的答案是您的应用程序是否可以解密它,用户最终也可以解密。
Spence

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

5

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

var str = "foo";
var sc = new SecureString();
foreach(char c in str) sc.appendChar(c);

甚至更
出色的人

这是一个班轮:var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
bigworld12 '16

4

我同意Spence(+1),但是如果您是出于学习或测试目的而使用它,则可以在字符串中使用foreach,并使用AppendChar方法将每个字符附加到安全字符串。


3

我只是想指出,所有的人说:“这不是点SecureString”,很多人问这个问题的可能是在何处,无论出于何种原因,合理与否,他们的应用程序并不特别在意有密码的临时副本以GC可用字符串的形式位于堆上,但他们必须使用接受的APISecureString对象。因此,您有一个不需要关心的应用程序密码是否在堆上,也许仅用于内部使用,并且仅存在于密码中,因为基础网络协议要求使用该密码,并且您发现存储密码的字符串不能用于例如设置远程PowerShell运行空间-但是没有简单,直接的一线内容即可创建SecureString所需的内容。这是一个小麻烦-但可能值得的,以确保真正的应用程序需要SecureString做不可试探作者使用System.StringSystem.Char[]中介机构。:-)


2

如果您想将a string到a 的转换压缩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,其初始化与数据保持在一起,并最终将其锁定以防止修改。


2

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

  1. 对于char阵列

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
  2. 而对于 string

    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 DaggAppendChar推荐。


0

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

private SecureString SecureStringConverter(string pass)
{
    SecureString ret = new SecureString();

    foreach (char chr in pass.ToCharArray())
        ret.AppendChar(chr);

    return ret;
}

1
这个答案是15个月前发布的。确实没有必要再次发布。
GSerg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.