Convertir une chaîne en SecureString

Réponses:

137

Vous ne le faites pas. La raison de l'utilisation de l'objet SecureString est d'éviter de créer un objet chaîne (qui est chargé en mémoire et y est conservé en texte brut jusqu'au garbage collection). Cependant, vous pouvez ajouter des caractères à un SecureString en les ajoutant.

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');
John Dagg
la source
13
"La combinaison est 12345... c'est le genre de chose qu'un idiot a sur ses bagages!"
Kolob Canyon du
8
Tout ce que je vois est*****
Ian Boyd
AppendCharne s'exécute pas avant l'exécution, donc ces caractères peuvent toujours être lus à partir de l'IL, n'est-ce pas? Peut-être qu'un obscurcissement lors de la compilation aiderait également ... c'est-à-dire si vous codez en dur des mots de passe.
samis
5
C'est un argument boiteux. Où obtenez-vous un mot de passe? Depuis un formulaire ou depuis une ligne de commande. Jusqu'à ce qu'ils créent une méthode pour lire une chaîne sécurisée directement à partir d'un périphérique ou des arguments de ligne de commande, nous devrons convertir une chaîne en SecureString.
Quarkly
1
@DonaldAirey vous obtenez un mot de passe d'un gestionnaire de secrets. Généralement, les secrets dont nous parlons ici ne sont pas des mots de passe utilisateur, mais des choses qui peuvent conduire à une élévation de privilèges ou à des fuites de données. Cela signifie que les mots de passe sont pour d'autres services et ne doivent pas être transmis sur les lignes de commande ou en clair sur les canaux réseau.
Barry Kelly
160

Il existe également une autre façon de convertir entre SecureStringet String.

1. Chaîne à SecureString

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

2. SecureString à String

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

Voici le lien

Hossein Narimani Rad
la source
4
C'est de loin la meilleure solution pour le cas d'utilisation le plus courant!
Dan Bechard
16
Il est inutile d'utiliser un SecureStringsi votre code crée un stringobjet avec la valeur que vous souhaitez sécuriser. Le but de SecureStringest d'éviter d'avoir la chaîne dans la mémoire gérée, afin qu'un attaquant examinant cette mémoire puisse repérer la valeur que vous souhaitez masquer. Étant donné que le NetworkCredentialconstructeur que vous appelez nécessite une chaîne, ce n'est pas la voie à suivre ... Bien sûr, votre code est un moyen facile de convertir vers et depuis un SecureString, mais son utilisation rend votre code aussi sûr que l'utilisation d'un simplestring
Gian Paolo
15
@GianPaolo bien que cela soit correct en théorie, en pratique, nous devons toujours l'utiliser SecureStringlorsque nous travaillons avec certaines bibliothèques. Et soyons honnêtes ici, si quelqu'un scanne activement la mémoire de votre application, vous avez déjà perdu. Même si vous avez utilisé correctement SecureString, ce que je n'ai jamais vu, il y aura d'autres données précieuses à extraire.
Jonathan Allen
1
@JonathanAllen: Vous avez probablement raison, mais uniquement parce que nous avons une culture de traitement de la sécurité après coup. Si vous créez un site Web de recettes, il est peu probable que la Corée du Nord essaie d'analyser la mémoire de votre programme. Si vous écrivez un logiciel bancaire, la menace est bien plus réelle.
Eric J.
58

La méthode ci-dessous permet de convertir une chaîne en chaîne sécurisée

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;
}
M2012
la source
26
+1, mais notez que la transmission du mot de passe en tant que paramètre de chaîne crée une instance de chaîne non chiffrée dans la mémoire gérée et va à l'encontre de l'objectif de «SecureString» en premier lieu. Il suffit de le signaler aux futures personnes qui viendront utiliser ce code.
Cody
19
@Cody C'est vrai, et c'est un bon point, mais beaucoup d'entre nous ne se soucient pas de savoir si SecureString est sécurisé ou non et ne l'utilisent que parce que certaines API Microsoft l'exigent comme paramètre.
Dan Bechard
3
@Cody Il s'avère que même la classe SecureString ne peut pas garder la chaîne chiffrée. C'est pourquoi MS envisage de rendre obsolète le type github.com/dotnet/platform-compat/blob/master/docs/DE0001.md .
Martin Brown
19

Vous pouvez suivre ceci:

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

Voici une astuce linq bon marché.

            SecureString sec = new SecureString();
            string pwd = "abc123"; /* Not Secure! */
            pwd.ToCharArray().ToList().ForEach(sec.AppendChar);
            /* and now : seal the deal */
            sec.MakeReadOnly();
grenadeCoder
la source
32
Cette réponse est un exercice pour voir combien de copies temporaires du texte brut peuvent être générées en un seul coup
Mike Caron
1
comme @ john-dagg l'a suggéré, l'idée est de NE PAS définir de chaîne avec votre mot de passe car si vous le faites, il n'y a plus aucun avantage à utiliser une chaîne de sécurité. Dans votre cas, vous avez mis le mot de passe en texte brut, vous ne sécurisez rien en utilisant plus tard une chaîne de sécurité. J'espère que vous comprenez que la chaîne de sécurité était destinée à sécuriser votre chaîne des personnes qui regardent le démontage ou un débogueur, alors voyez ce qui se trouve dans l'IL / mémoire.
user734028
8

Je vais jeter ça là-bas. Pourquoi?

Vous ne pouvez pas simplement changer toutes vos chaînes en chaînes sécurisées et soudainement votre application est "sécurisée". La chaîne sécurisée est conçue pour garder la chaîne cryptée aussi longtemps que possible, et uniquement décryptée pendant une très courte période de temps, effaçant la mémoire après qu'une opération a été effectuée sur elle.

Je risquerais de dire que vous pourriez avoir des problèmes au niveau de la conception à résoudre avant de vous soucier de la sécurisation de vos chaînes d'application. Donnez-nous plus d'informations sur ce que vous essayez de faire et nous pourrons peut-être mieux vous aider.

Spence
la source
1
Je veux juste l'utiliser pour définir le mot de passe pour ProcessStartInfo et exécuter mon exe en tant qu'utilisateur différent. Cela a fonctionné pour moi ...
Developer404
4
Mon application est sécurisée en l'exécutant sur un système sécurisé. Je me fiche du fait que cette chaîne particulière est chiffrée en mémoire. Il y a beaucoup plus d'informations vitales sur ce système dont il faut s'inquiéter en cas de compromission. SecureString est simplement requis par une API Microsoft que mon programme doit utiliser. Cela implique que le développeur considère son propre cas d'utilisation et détermine si la conversion de chaînes en SecureStrings est une opération valide dans le contexte.
Dan Bechard
Donc, cette méthode n'empêchera pas quelqu'un de voir le mot de passe s'il utilise un décompilateur comme DotPeek? Existe-t-il un moyen de masquer les chaînes dans ce cas?
M.Parent
Il existe quelques méthodes, selon la menace que vous essayez de vaincre. Si c'est pour protéger les informations des utilisateurs de quiconque sauf de l'administrateur local, vous pouvez utiliser les méthodes DPAPI sous Windows pour crypter un fichier et y stocker un secret, le lire dans une chaîne sécurisée, puis le jeter. S'il s'agit d'un secret d'entreprise, la réponse courte est si votre application peut le déchiffrer, l'utilisateur peut éventuellement le faire.
Spence
6
unsafe 
{
    fixed(char* psz = password)
        return new SecureString(psz, password.Length);
}
hypersw
la source
5

pas de linq fantaisie, ne pas ajouter tous les caractères à la main, simplement et simplement:

var str = "foo";
var sc = new SecureString();
foreach(char c in str) sc.appendChar(c);
garglblarg
la source
encore plus chic, pas besoin de définir une variable
bigworld12
voici un one liner:var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
bigworld12
4

Je suis d'accord avec Spence (+1), mais si vous le faites pour apprendre ou tester des pourposes, vous pouvez utiliser un foreach dans la chaîne, en ajoutant chaque caractère à la chaîne de sécurité en utilisant la méthode AppendChar.

Jonathan
la source
3

Je veux juste signaler à toutes les personnes qui disent: "Ce n'est pas le but de SecureString", que bon nombre des personnes qui posent cette question peuvent se trouver dans une application où, pour une raison quelconque, justifiée ou non, elles ne sont pas particulièrement préoccupées par le fait d'avoir une copie temporaire du sit mot de passe sur le tas comme une chaîne de GC-mesure, mais ils doivent utiliser une API qui n'accepte des objets. Donc, vous avez une application où vous ne vous souciez pasSecureStringsi le mot de passe est sur le tas, peut-être qu'il est à usage interne uniquement et le mot de passe est uniquement là parce qu'il est requis par les protocoles réseau sous-jacents, et vous trouvez que cette chaîne où le mot de passe est stocké ne peut pas être utilisée pour, par exemple, configurer un PowerShell distant Runspace - mais il n'y a pas de one-liner simple et simple pour créer ce SecureStringdont vous avez besoin. Il est un inconvénient mineur - mais probablement la peine de veiller à ce que les applications qui vraiment font besoin d' SecureStringne pas tenter les auteurs à l' utilisation System.Stringou System.Char[]intermédiaires. :-)

Jonathan Gilbert
la source
2

Si vous souhaitez compresser la conversion de a stringen a SecureStringen une LINQinstruction, vous pouvez l'exprimer comme suit:

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

Cependant, gardez à l'esprit que l'utilisation LINQn'améliore pas la sécurité de cette solution. Il souffre du même défaut que toute conversion de stringvers SecureString. Tant que l'original stringreste en mémoire, les données sont vulnérables.

Cela étant dit, ce que l'instruction ci-dessus peut offrir est de garder ensemble la création du SecureString, son initialisation avec des données et enfin le verrouiller contre toute modification.

cel sharp
la source
2

Les 2 extensions suivantes devraient faire l'affaire:

  1. Pour un chartableau

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

Merci à John Dagg pour la AppendCharrecommandation.

Peet
la source
0

vous pouvez utiliser ce simple script

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

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

    return ret;
}
nadir
la source
1
Cette réponse a été publiée il y a 15 mois . Il n'était vraiment pas nécessaire de le publier à nouveau.
GSerg