How to properly convert SecureString to String

本文讨论了.NET Framework中SecureString的正确使用方式,特别是在将其转换为明文字符串时的注意事项。文章提供了两个错误示例,并给出了一种正确的实现方法,通过try/finally块确保分配的内存得到释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

It feels like forever since SecureString has been introduced in the .Net Framework and yet I keep seeing it being mishandled, in particular by code that returns or receives passwords in clear text, so in this post I’ll show what you should be looking for when doing code reviews and finding conversions from SecureString to string.

The main idea with SecureString is that you would never store a password or other textual secret in plain text, unencrypted memory – at least not in a System.String instance. Unfortunately, SecureString was introduced in the framework only after plenty of APIs were built and shipped using passwords stored in String, such as System.Net.NetworkCredential, so an application that must use these APIs has no option but to convert SecureStrings to strings.

However, the SecureString class itself doesn’t provide any methods to get back a plain string with its content, exactly to discourage this type of usage. What a developer has to do is use functions from System.Runtime.InteropServices.Marshal to get a native buffer with the plain string, marshal the value into a managed string then – very importantly – free the native buffer.

And this is where I’ve seen people people making mistakes. You can certainly spot the problems in the following functions:

public static string BAD_ConvertToUnsecureString(this SecureString securePassword)
{
    IntPtr unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
    var s = Marshal.PtrToStringUni(unmanagedString);
    Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
    return s;
}

public static string REALLY_BAD_ConvertToUnsecureString(this SecureString securePassword)
{
    IntPtr unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
    return Marshal.PtrToStringUni(unmanagedString);
}

The first one is almost ok, but if an exception happens after the native buffer is allocated then we leak that password. The second one is just plain wrong; the developer completely forgot to free the native buffer, introducing an unconditional leak of that password.

I’ve seen both mistakes being freely cut-and-paste because the original code was embedded in a larger function that was doing multiple things, so the details of the conversion were easy to overlook. Lacking a simple, reusable function leads to that, so don’t let these bugs creep into your project.

The correct implementation is to use a try/finally block to free the native buffer. Here’s an example, using SecureStringToGlobalAllocUnicode and ZeroFreeGlobalAllocUnicode:

public static string ConvertToUnsecureString(this SecureString securePassword)
{
    if (securePassword == null)
        throw new ArgumentNullException("securePassword");

    IntPtr unmanagedString = IntPtr.Zero;
    try
    {
        unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
        return Marshal.PtrToStringUni(unmanagedString);
    }
    finally
    {
        Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
    }
}

Please understand that a little village bursts on fire every time you call such a function, but if you do need it, write it like this, so there’s no excuse for anyone to write that code again.

The extension method syntax makes it easy to call the conversion as if it was part of SecureString itself:

SecureString password = someCodeToGetSecureString();
var credentials = new NetworkCredential(userName, password.ConvertToUnsecureString())

While at it you may want to provide the counterpart that converts a plain String to a SecureString. Following the same pattern as above we’ll have:

public static SecureString ConvertToSecureString(this string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    unsafe
    {
        fixed (char* passwordChars = password)
        {
            var securePassword = new SecureString(passwordChars, password.Length);
            securePassword.MakeReadOnly();
            return securePassword;
        }
    }
}

The important point here is to mark the secure string as read-only before returning it – it is very unlikely that you’ll need to edit a secure string that was created from an existing string. You’ll also note that in the above example I used unsafe code to initialize the SecureString from its fixed/char* representation, which is about 10x faster than using AppendChar. If you are not allowed to use unsafe code, don’t worry, just write it using AppendChar and it works fine.

I’m not proud to have clear text passwords in my process memory, but we’ll have to live with it until the day somebody updates the framework to use SecureString everywhere, particularly in System.Net.

If you need to learn more about SecureString this post is a great start:http://blogs.msdn.com/shawnfa/archive/2004/05/27/143254.aspx.


Referenced from: http://blogs.msdn.com/b/fpintos/archive/2009/06/12/how-to-properly-convert-securestring-to-string.aspx

内容概要:本文档详细介绍了一个基于MATLAB实现的跨尺度注意力机制(CSA)结合Transformer编码器的多变量时间序列预测项目。项目旨在精准捕捉多尺度时间序列特征,提升多变量时间序列的预测性能,降低模型计算复杂度与训练时间,增强模型的解释性和可视化能力。通过跨尺度注意力机制,模型可以同时捕获局部细节和全局趋势,显著提升预测精度和泛化能力。文档还探讨了项目面临的挑战,如多尺度特征融合、多变量复杂依赖关系、计算资源瓶颈等问题,并提出了相应的解决方案。此外,项目模型架构包括跨尺度注意力机制模块、Transformer编码器层和输出预测层,文档最后提供了部分MATLAB代码示例。 适合人群:具备一定编程基础,尤其是熟悉MATLAB和深度学习的科研人员、工程师和研究生。 使用场景及目标:①需要处理多变量、多尺度时间序列数据的研究和应用场景,如金融市场分析、气象预测、工业设备监控、交通流量预测等;②希望深入了解跨尺度注意力机制和Transformer编码器在时间序列预测中的应用;③希望通过MATLAB实现高效的多变量时间序列预测模型,提升预测精度和模型解释性。 其他说明:此项目不仅提供了一种新的技术路径来处理复杂的时间序列数据,还推动了多领域多变量时间序列应用的创新。文档中的代码示例和详细的模型描述有助于读者快速理解和复现该项目,促进学术和技术交流。建议读者在实践中结合自己的数据集进行调试和优化,以达到最佳的预测效果。
Implement the classic method for composing secret messages called a square code. Given an English text, output the encoded version of that text. First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased. Then, the normalized characters are broken into rows. These rows can be regarded as forming a rectangle when printed with intervening newlines. For example, the sentence ```text "If man was meant to stay on the ground, god would have given us roots." ``` is normalized to: ```text "ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" ``` The plaintext should be organized into a rectangle as square as possible. The size of the rectangle should be decided by the length of the message. If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that: - `r * c >= length of message`, - and `c >= r`, - and `c - r <= 1`. Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: ```text "ifmanwas" "meanttos" "tayonthe" "groundgo" "dwouldha" "vegivenu" "sroots " ``` The coded message is obtained by reading down the columns going left to right. The message above is coded as: ```text "imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" ``` Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space. ```text "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " ``` 上述为题目要求,请用C语言实现,函数声明如下: char *ciphertext(const char *input)
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值