【问题标题】:Using SecureString使用安全字符串
【发布时间】:2010-03-10 20:00:45
【问题描述】:

这可以简化为单行吗?只要secureString被正确初始化,就可以完全重写它。

SecureString secureString = new SecureString ();
foreach (char c in "fizzbuzz".ToCharArray())
{
    secureString.AppendChar (c);
}

【问题讨论】:

标签: c# security securestring


【解决方案1】:

只需使用 NetworkCredential。它内置了转换逻辑。

SecureString ss = new NetworkCredential("", "fizzbuzz").SecurePassword;

正如其他人所指出的,所有这些技术都剥夺了 SecureString 的安全优势,但在某些情况下(例如单元测试),这可能是可以接受的。

更新:

如 cmets 中所述,NetworkCredential 还可用于将 SecureString 转换回字符串。

string s = new NetworkCredential("", ss).Password;

【讨论】:

  • 在.Net 4.0之前不可用
  • @JohannesOvermann,双向是什么意思? (据我所知,NetworkCredential 使用纯文本密码或 SecureString 密码,但在前一种情况下仅公开纯文本密码。)
  • @CodeFox:我的意思是它可以用来翻译 String -> SecureString 和 SecureString -> String。我认为它总是消耗两者并且总是暴露两者。但是从您的问题来看,我认为 SecureString -> String 不起作用?
  • @JohannesOvermann,是的 - 这是我在阅读 NetworkCredential 类的 MSDN 文档后的假设。我已经尝试过了,现在可以确认您的原始评论。再次感谢!
  • @CodeFox:感谢您试用并确认它确实有效!
【解决方案2】:

你可以使用 Linq:

"fizzbuzz".ToCharArray().ToList().ForEach(p => secureString.AppendChar(p));

【讨论】:

  • 我想我可以把它放到一个扩展方法中来得到我想要的东西:processInfo.Password = new SecureSring ().FromString ("fizzbuzz")
  • 您可以通过以下方式避免额外的 .ToList() 操作:Array.ForEach("fizzbuzz".ToCharArray(), secureString.AppendChar);
  • 你不必声明ToCharArray,Linq会自动枚举为char数组。
  • 这仍然是 2 班轮吗?你仍然需要声明secureString
  • 至少在 .NET 的更高版本(比如 4.5)中,这是可能的"fizzbuzz".ForEach(secureString.AppendChar)
【解决方案3】:

除了使用不安全的代码和char*,没有(很多)更好的方法了。

这里的重点是不要将 SecureString 内容复制到普通字符串或从普通字符串复制。常量"fizzbuzz" 常量就是这里的安全漏洞。

【讨论】:

  • 打败我——+1。加上您需要进行的额外更改以允许不安全的代码否定代码行上的任何“节省”。
  • 大多数密码在大多数软件中不是以字符串形式出现,然后需要转换为 SecureString 吗?不确定“不要从普通字符串中复制 SecureString 内容”是什么意思。在正常情况下,这将是字符串密码。 “fizzbuzz”只是一种敬意。
  • 是的,这大大降低了 SecureString 的可用性。
  • 如果您从击键中收集 SecureString,您实际上并没有原始字符串。我相信,这就是 SecureString 的初衷。
  • 我还没有找到一个 Q&A 来讨论如何捕获您希望在开始的过程中确保安全的字符串。例如,假设我从 Windows 表单上的密码表单控件的用户输入中获取密码。我怎样才能安全地获得该输入?在我从控件中获取它的那一刻,它是否已经在string 中,否定了我保护它的尝试?在从控件中检索 string 并将其放入我的 SecureString 后,我可以强制垃圾回收吗?
【解决方案4】:
var s = "fizzbuzz".Aggregate(new SecureString(), (ss, c) => { ss.AppendChar(c); return ss; });

【讨论】:

  • 这很优雅。
【解决方案5】:

Sascha 用方法组替换 lambda 的答案略有改进

"fizzbuzz".ToCharArray().ToList().ForEach(ss.AppendChar);

【讨论】:

    【解决方案6】:

    由于SecureString 使用IDispose 接口。你实际上可以这样做。

    SecureString secure = new SecureString();
    foreach(var character in data.ToCharArray())
        secure.AppendChar(character);
    

    基本上data 将是一个参数。

    如果您使用using 来帮助减轻资源;您需要注意范围。但这可能是一个有益的选择,具体取决于使用情况。

    更新:

    你实际上可以做一个完整的方法签名:

    public static SecureString ConvertStringToSecureString(this string data)
    {
         var secure = new SecureString();
         foreach(var character in data.ToCharArray())
             secure.AppendChar(character);
    
         secure.MakeReadOnly();
         return secure;
         
    }
    

    对于你想要做的解密:

    public static string ConvertSecureStringToString(this SecureString data)
    {
         var pointer = IntPtr.Zero;
         try
         {
              pointer = Marshal.SecureStringToGlobalAllocUnicode(data);
              return Marshal.PtrToStringUni(pointer);
         }
         finally
         {
              Marshal.ZeroFreeGlobalAllocUnicode(pointer);
         }
    }
    

    下面的article 也会给你一些额外的信息。

    【讨论】:

    • 为什么 MS 不把这个添加到框架中?如果您无法访问该值,则该类完全没用。似乎他们 (MS) 要么真的不希望人们使用 SecureString,要么比我之前指责的更无能。
    【解决方案7】:

    这是来自 .NET 的 NetworkCredential 类如何做到这一点:

    SecureString secureString;
    fixed (char* chPtr = plainString)
      secureString = new SecureString(chPtr, plainString.Length);
    

    丑陋但可能是最有效的。

    【讨论】:

    • 注意fixed的使用需要unsafe块,而这又需要编译器开关/unsafe
    【解决方案8】:

    代码量最少,因为.ToList() 不需要:

    Array.ForEach("fizzbuzz".ToCharArray(), secureString.AppendChar);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-17
      • 1970-01-01
      • 2011-03-26
      • 2019-02-17
      • 1970-01-01
      • 2011-12-03
      • 2015-08-19
      • 1970-01-01
      相关资源
      最近更新 更多