Quand aurais-je besoin d'une SecureString dans .NET?



Answers

Beaucoup de bonnes réponses Voici un bref résumé de ce qui a été discuté.

Microsoft a implémenté la classe SecureString dans le but de fournir une meilleure sécurité avec des informations sensibles (comme les cartes de crédit, les mots de passe, etc.). Il fournit automatiquement:

  • cryptage (dans le cas de vidages mémoire ou de mise en cache de pages)
  • épingler dans la mémoire
  • possibilité de marquer en lecture seule (pour éviter toute modification ultérieure)
  • construction sécurisée en ne permettant PAS l'insertion d'une chaîne constante

À l'heure actuelle, SecureString est limité mais s'attend à une meilleure adoption à l'avenir.

Sur la base de ces informations, le constructeur de SecureString ne doit pas simplement prendre une chaîne et la découper en tableau car la chaîne épelée va à l'encontre du but de SecureString.

Information additionnelle:

  • Un post du blog de sécurité .NET qui parle à peu près de la même chose que celui-ci.
  • Et un one revisitant et mentionnant un outil qui peut déverser le contenu de SecureString.

Edit: J'ai trouvé difficile de choisir la meilleure réponse car il y a de bonnes informations dans plusieurs; dommage qu'il n'y ait pas d'options de réponse assistée.

Question

J'essaye de creuser l'objectif de SecureString de .NET. De MSDN:

Une instance de la classe System.String est à la fois immuable et, lorsqu'elle n'est plus nécessaire, ne peut pas être planifiée par programmation pour la récupération de place. c'est-à-dire que l'instance est en lecture seule après sa création et qu'il n'est pas possible de prédire quand l'instance sera supprimée de la mémoire de l'ordinateur. Par conséquent, si un objet String contient des informations sensibles telles qu'un mot de passe, un numéro de carte de crédit ou des données personnelles, les informations risquent d'être révélées après leur utilisation car votre application ne peut pas supprimer les données de la mémoire de l'ordinateur.

Un objet SecureString est similaire à un objet String en ce qu'il a une valeur de texte. Cependant, la valeur d'un objet SecureString est automatiquement cryptée, peut être modifiée jusqu'à ce que votre application la marque comme étant en lecture seule, et peut être supprimée de la mémoire de l'ordinateur par votre application ou le garbage collector .NET Framework.

La valeur d'une instance de SecureString est automatiquement chiffrée lorsque l'instance est initialisée ou lorsque la valeur est modifiée. Votre application peut rendre l'instance immuable et empêcher toute modification supplémentaire en appelant la méthode MakeReadOnly.

Le cryptage automatique est-il la grande récompense?

Et pourquoi je ne peux pas dire:

SecureString password = new SecureString("password");

au lieu de

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

Quel aspect de SecureString me manque?




L'un des grands avantages d'un SecureString est qu'il est supposé éviter la possibilité de stocker vos données sur le disque en raison de la mise en cache des pages. Si vous avez un mot de passe en mémoire, puis chargez un grand programme ou ensemble de données, votre mot de passe peut être écrit dans le fichier d'échange lorsque votre programme est paginé. Avec un SecureString, au moins les données ne resteront pas indéfiniment sur votre disque en texte clair.




Réponse courte

pourquoi je ne peux pas juste dire:

SecureString password = new SecureString("password");

Parce que maintenant vous avez un password de password en mémoire; avec aucun moyen de l'effacer - ce qui est exactement le point de SecureString .

Longue réponse

La raison pour laquelle SecureString existe est que vous ne pouvez pas utiliser ZeroMemory pour effacer les données sensibles lorsque vous avez terminé. Il existe pour résoudre un problème qui existe en raison de la CLR.

Dans une application native standard, vous appelez SecureZeroMemory :

Remplit un bloc de mémoire avec des zéros.

Remarque : SecureZeroMemory est identique à ZeroMemory , sauf que le compilateur ne l'optimisera pas.

Le problème est que vous ne pouvez pas appeler ZeroMemory ou SecureZeroMemory dans .NET. Et dans les chaînes .NET sont immuables; vous ne pouvez même pas écraser le contenu de la chaîne comme vous pouvez le faire dans d'autres langues:

//Wipe out the password
for (int i=0; i<password.Length; i++)
   password[i] = \0;

Alors que peux-tu faire? Comment pouvons-nous fournir à .NET la possibilité d'effacer un mot de passe ou un numéro de carte de crédit de la mémoire lorsque nous en avons fini?

La seule façon de le faire serait de placer la chaîne dans un bloc de mémoire natif , où vous pourrez alors appeler ZeroMemory . Un objet mémoire natif tel que:

  • un BSTR
  • un HGLOBAL
  • CoTaskMem mémoire non gérée

SecureString redonne la capacité perdue

Dans .NET, les chaînes ne peuvent pas être effacées lorsque vous en avez fini avec elles:

  • ils sont immuables; vous ne pouvez pas écraser leur contenu
  • vous ne pouvez pas en Dispose
  • leur nettoyage est à la merci du ramasse-miettes

SecureString existe comme un moyen de contourner la sécurité des chaînes et de garantir leur nettoyage lorsque vous en avez besoin.

Vous avez posé la question:

pourquoi je ne peux pas juste dire:

SecureString password = new SecureString("password");

Parce que maintenant vous avez un password de password en mémoire; sans moyen de l'essuyer. Il est coincé là jusqu'à ce que le CLR arrive à décider de réutiliser cette mémoire. Vous nous avez remis tout de suite où nous avons commencé; une application en cours d'exécution avec un mot de passe dont nous ne pouvons pas nous débarrasser, et où un vidage de la mémoire (ou Process Monitor) peut voir le mot de passe.

SecureString utilise l'API Data Protection pour stocker la chaîne chiffrée en mémoire; De cette façon, la chaîne n'existera pas dans les fichiers d'échange, les vidages sur incident, ou même dans la fenêtre des variables locales avec un collègue regardant par-dessus votre avis.

Comment puis-je lire le mot de passe?

Alors est la question: comment puis-je interagir avec la chaîne? Vous ne voulez absolument pas une méthode comme:

String connectionString = secureConnectionString.ToString()

parce que maintenant vous êtes de retour là où vous avez commencé - un mot de passe dont vous ne pouvez pas vous débarrasser. Vous voulez forcer les développeurs à gérer correctement la chaîne sensible afin qu'elle puisse être effacée de la mémoire.

C'est pourquoi .NET fournit trois fonctions d'assistance pratiques pour rassembler un SecureString dans une mémoire non gérée:

Vous convertissez la chaîne en un blob de mémoire non géré, le gérez, puis l'effacez à nouveau.

Certaines API acceptent SecureStrings . Par exemple dans ADO.net 4.5 le SqlConnection.Credential prend un ensemble SqlCredential :

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

Vous pouvez également changer le mot de passe dans une chaîne de connexion:

SqlConnection.ChangePassword(connectionString, cred, newPassword);

Et il y a beaucoup d'endroits à l'intérieur de .NET où ils continuent à accepter une corde plate à des fins de compatibilité, puis ils se retournent rapidement pour la mettre dans un SecureString.

Comment mettre du texte dans le SecureString?

Cela laisse toujours le problème:

Comment obtenir un mot de passe dans SecureString en premier lieu?

C'est le défi, mais le but est de vous faire penser à la sécurité.

Parfois, la fonctionnalité est déjà fournie pour vous. Par exemple, le contrôle WPF PasswordBox peut vous renvoyer le mot de passe entré en tant que SecureString directement:

Propriété PasswordBox.SecurePassword

Obtient le mot de passe actuellement détenu par le PasswordBox tant que SecureString .

Cela est utile car, partout où vous avez passé une chaîne brute, le système de type se plaint que SecureString est incompatible avec String. Vous voulez aller le plus longtemps possible avant de devoir convertir votre SecureString en chaîne normale.

La conversion d'un SecureString est assez facile:

  • SecureStringToBSTR
  • PtrToStringBSTR

un péché:

private static string CreateString(SecureString secureString)
{
    IntPtr intPtr = IntPtr.Zero;
    if (secureString == null || secureString.Length == 0)
    {
        return string.Empty;
    }
    string result;
    try
    {
        intPtr = Marshal.SecureStringToBSTR(secureString);
        result = Marshal.PtrToStringBSTR(intPtr);
    }
    finally
    {
        if (intPtr != IntPtr.Zero)
        {
            Marshal.ZeroFreeBSTR(intPtr);
        }
    }
    return result;
}

Ils ne veulent vraiment pas que tu le fasses.

Mais comment puis-je obtenir une chaîne dans un SecureString? Eh bien ce que vous devez faire est d'arrêter d'avoir un mot de passe dans une chaîne en premier lieu. Tu avais besoin de l'avoir dans autre chose . Même un tableau Char[] serait utile.

C'est à ce moment que vous pouvez ajouter chaque caractère et effacer le texte en clair lorsque vous avez terminé:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

Vous avez besoin de votre mot de passe stocké dans une mémoire que vous pouvez effacer. Chargez-le dans le SecureString à partir de là.

tl; dr: SecureString existe pour fournir l'équivalent de ZeroMemory .

Certaines personnes ne voient pas l'intérêt d' effacer le mot de passe de l'utilisateur de la mémoire lorsqu'un périphérique est verrouillé ou d' effacer les touches de la mémoire après leur authentification . Ces personnes n'utilisent pas SecureString.




J'arrêterais d'utiliser SecureString. On dirait que les gars de PG abandonnent le support pour cela. Peut-être même le tirer dans le futur - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .

Nous devrions supprimer le cryptage de SecureString sur toutes les plates-formes dans .NET Core - Nous devrions obsolète SecureString - Nous ne devrions probablement pas exposer SecureString dans .NET Core




Je crois que la raison pour laquelle vous devez ajouter des caractères à la place d'une instanciation plate est qu'en arrière-plan, passer le mot de passe au constructeur de SecureString met cette chaîne "password" en mémoire en défaisant la fonction de chaîne sécurisée.

En ajoutant un personnage à la fois, il ne fait que mettre en mémoire un personnage qui n'est pas nécessairement adjacent physiquement, ce qui rend beaucoup plus difficile la reconstruction de la chaîne originale. Je peux me tromper ici, mais c'est ainsi que cela m'a été expliqué.

Le but de la classe est d'empêcher l'exposition de données sécurisées via un vidage de mémoire ou un outil similaire.




Links