Convertir cadena a SecureString


Respuestas:


137

Usted no Toda la razón para usar el objeto SecureString es evitar crear un objeto de cadena (que se carga en la memoria y se mantiene allí en texto sin formato hasta la recolección de basura). Sin embargo, puede agregar caracteres a SecureString agregándolos.

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
"La combinación es 12345... ¡ese es el tipo de cosas que un idiota tiene en su equipaje!"
Kolob Canyon

8
Todo lo que veo es*****
Ian Boyd el

AppendCharno se ejecuta hasta el tiempo de ejecución, por lo que esos caracteres aún se pueden leer desde el IL, ¿correcto? Tal vez algo de ofuscación en tiempo de compilación también ayudaría ... es decir, si está codificando contraseñas.
samis

55
Ese es un argumento poco convincente. ¿Dónde obtienes una contraseña? Desde un formulario o desde una línea de comando. Hasta que creen un método para leer una cadena segura directamente desde un dispositivo o argumentos de línea de comando, necesitaremos convertir una cadena en una SecureString.
Quarkly

1
@DonaldAirey obtienes una contraseña de un administrador de secretos. En general, los secretos de los que estamos hablando aquí no son las contraseñas de los usuarios, sino cosas que potencialmente conducen a la escalada de privilegios o a la fuga de datos. Eso significa que las contraseñas son para otros servicios y no deben pasarse en las líneas de comando o en los canales de red transparentes.
Barry Kelly

160

También hay otra forma de convertir entre SecureStringy String.

1. Cadena a SecureString

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

2. SecureString a String

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

Aqui esta el enlace


44
¡Esta es la mejor solución para el caso de uso más común!
Dan Bechard el

16
No tiene sentido usar a SecureStringsi su código crea un stringobjeto con el valor que desea proteger. El objetivo SecureStringes evitar tener la cadena en la memoria administrada, por lo que un atacante que examine esa memoria puede detectar el valor que desea ocultar. Dado que el NetworkCredentialconstructor al que llama requiere una cadena, ese no es el camino a seguir ... Claro, su código es una forma fácil de convertir ay desde un SecureString, pero usarlo hace que su código sea tan seguro como usar un simplestring
Gian Paolo

15
@GianPaolo si bien eso es correcto en teoría, en la práctica todavía tenemos que usarlo SecureStringcuando trabajamos con algunas bibliotecas. Y seamos honestos aquí, si alguien está escaneando activamente la memoria de su aplicación, entonces ya ha perdido. Incluso si ha utilizado SecureString correctamente, lo que nunca he visto, habrá otros datos valiosos para extraer.
Jonathan Allen

1
@ JonathanAllen: Probablemente tengas razón, pero solo porque tenemos una cultura de tratar la seguridad como una ocurrencia tardía. Si está creando un sitio web de recetas, es probable que Corea del Norte no intente escanear la memoria de su programa. Si está escribiendo software bancario, la amenaza es mucho más real.
Eric J.

58

El siguiente método ayuda a convertir cadenas en cadenas seguras

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, pero tenga en cuenta que pasar la contraseña como un parámetro de cadena crea una instancia de cadena sin cifrar en la memoria administrada y, en primer lugar, anula el propósito de 'SecureString'. Solo señalo esto para las futuras personas que vienen y usan este código.
Cody

19
@Cody Eso es cierto, y un buen punto, pero a muchos de nosotros no nos importa si SecureString es seguro o no, y solo lo estamos usando porque algunas API de Microsoft lo requieren como parámetro.
Dan Bechard el

3
@Cody Resulta que incluso la clase SecureString no puede mantener la cadena encriptada. Es por eso que MS está considerando obsoleto el tipo github.com/dotnet/platform-compat/blob/master/docs/DE0001.md .
Martin Brown

19

Puedes seguir esto:

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

11

Aquí hay un truco barato de linq.

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

32
Esta respuesta es un ejercicio para ver cuántas copias temporales del texto sin formato se pueden generar de una sola vez
Mike Caron

1
como sugirió @ john-dagg, la idea es NO establecer una cadena con su contraseña porque si lo hace, no queda ninguna ventaja para usar una cadena de seguridad. En el caso de que haya ingresado la contraseña en texto plano, no está asegurando nada al utilizar una cadena de seguridad. Espero que comprenda que la cadena de seguridad estaba destinada a asegurar su cadena de personas que miran el desmontaje o un depurador, así que vea lo que hay en la memoria / IL.
user734028

8

Voy a tirar esto por ahí. ¿Por qué?

No puede simplemente cambiar todas sus cadenas a cadenas seguras y de repente su aplicación es "segura". La cadena segura está diseñada para mantener la cadena encriptada durante el mayor tiempo posible, y solo se desencripta por un período de tiempo muy corto, borrando la memoria después de que se haya realizado una operación.

Me arriesgaría a decir que puede tener algunos problemas de nivel de diseño con los que lidiar antes de preocuparse por proteger las cadenas de su aplicación. Danos más información sobre lo que estás tratando de hacer y podremos ayudarte mejor.


1
Solo quiero usarlo para establecer una contraseña para ProcessStartInfo y ejecutar mi exe como un usuario diferente ... Eso funcionó para mí ...
Developer404

44
Mi aplicación está asegurada ejecutándola en un sistema seguro. No podría importarme menos que esta cadena en particular esté encriptada en la memoria. Hay mucho más información vital sobre este sistema de la que preocuparse si alguna vez se ve comprometida. SecureString es simplemente requerido por una API de Microsoft que mi programa necesita utilizar. Está implícito que el desarrollador considere su propio caso de uso y determine si convertir Strings a SecureStrings es una operación válida en contexto.
Dan Bechard el

Entonces, ¿este método no impedirá que alguien vea la contraseña si usa un descompilador como DotPeek? ¿Hay alguna manera de ocultar cadenas en este caso?
M. Padres

Existen algunos métodos, dependiendo de la amenaza que intentes derrotar. Si se trata de proteger la información de los usuarios de cualquier persona que no sea el administrador local, puede utilizar los métodos DPAPI en Windows para cifrar un archivo y almacenar un secreto allí, leerlo en una cadena segura y luego tirarlo. Si se trata de un secreto de la empresa, la respuesta breve es si su aplicación puede descifrarlo, al igual que el usuario eventualmente.
Spence

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

5

sin linq elegante, sin agregar todos los caracteres a mano, simplemente simple y llanamente:

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

incluso más elegante, no hay necesidad de definir una variable
bigworld12

aquí hay una var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
frase

4

Estoy de acuerdo con Spence (+1), pero si lo está haciendo para aprender o probar los propósitos, puede usar un foreach en la cadena, agregando cada carácter a la cadena de seguridad utilizando el método AppendChar.


3

Sólo quiero señalar a todo el pueblo diciendo: "Ese no es el punto de SecureString", que muchas de las personas que piden esta pregunta podría ser en una aplicación en la que, por cualquier razón, justificada o no, son no particularmente preocupados acerca de tener una copia temporal de la contraseña se encuentra en el montón como una cadena compatible con GC, pero tienen que usar una API que solo acepte SecureStringobjetos. Entonces, tienes una aplicación donde no te importasi la contraseña está en el montón, tal vez es solo para uso interno y la contraseña solo está allí porque es requerida por los protocolos de red subyacentes, y encuentra que esa cadena donde se almacena la contraseña no se puede usar, por ejemplo, para configurar un PowerShell remoto Runspace, pero no hay una línea sencilla y directa para crear lo que SecureStringnecesita. Es un inconveniente menor - pero probablemente vale la pena para asegurarse de que las aplicaciones que realmente hacen es necesario SecureStringNo tiente a los autores el uso System.Stringo System.Char[]intermediarios. :-)


2

Si desea comprimir la conversión de stringa a SecureStringen una LINQdeclaración, puede expresarla de la siguiente manera:

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

Sin embargo, tenga en cuenta que el uso LINQno mejora la seguridad de esta solución. Sufre el mismo defecto que cualquier conversión de stringa SecureString. Mientras el original stringpermanezca en la memoria, los datos son vulnerables.

Dicho esto, lo que la declaración anterior puede ofrecer es mantener juntos la creación del SecureString , su inicialización con datos y finalmente bloquearlo de la modificación.


2

Las siguientes 2 extensiones deberían hacer el truco:

  1. Para una charmatriz

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
  2. Y para 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;
    }

Gracias a John Dagg por la AppendCharrecomendación.


0

puedes usar este simple script

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

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

    return ret;
}

1
Esta respuesta fue publicada hace 15 meses . Realmente no había necesidad de publicarlo nuevamente.
GSerg
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.