N'hésitez pas à me corriger si mes hypothèses sont erronées ici, mais laissez-moi vous expliquer pourquoi je demande.
Tiré de MSDN, un SecureString
:
Représente un texte qui doit rester confidentiel. Le texte est crypté pour plus de confidentialité lors de son utilisation et supprimé de la mémoire de l'ordinateur lorsqu'il n'est plus nécessaire.
Je comprends cela, il est parfaitement logique de stocker un mot de passe ou d'autres informations privées dans un SecureString
sur un System.String
, car vous pouvez contrôler comment et quand il est réellement stocké en mémoire, car un System.String
:
est à la fois immuable et, lorsqu'il n'est plus nécessaire, ne peut pas être programmé pour la collecte des ordures; en d'autres termes, l'instance est en lecture seule après sa création et 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, il existe un risque que les informations soient 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.
Cependant, dans le cas d'une application GUI (par exemple, un client ssh), le SecureString
doit être construit à partir d'un System.String
. Tous les contrôles de texte utilisent une chaîne comme type de données sous-jacent .
Cela signifie donc que chaque fois que l'utilisateur appuie sur une touche, l'ancienne chaîne qui s'y trouvait est supprimée et une nouvelle chaîne est créée pour représenter la valeur à l'intérieur de la zone de texte, même si vous utilisez un masque de mot de passe. Et nous ne pouvons pas contrôler quand ou si l'une de ces valeurs est supprimée de la mémoire .
Il est maintenant temps de vous connecter au serveur. Devine quoi? Vous devez passer une chaîne sur la connexion pour l'authentification . Convertissons donc notre SecureString
en un System.String
.... et maintenant nous avons une chaîne sur le tas sans aucun moyen de la forcer à passer par la récupération de place (ou d'écrire des 0 dans son tampon).
Mon point est : peu importe ce que vous faites, quelque part le long de la ligne, qui SecureString
est va être transformé en un System.String
, ce qui signifie qu'il sera au moins exist sur le tas à un moment donné (sans aucune garantie de la collecte des ordures).
Mon point n'est pas : s'il existe des moyens de contourner l'envoi d'une chaîne à une connexion ssh, ou de contourner le fait qu'un contrôle stocke une chaîne (créer un contrôle personnalisé). Pour cette question, vous pouvez remplacer "connexion ssh" par "formulaire de connexion", "formulaire d'inscription", "formulaire de paiement", "aliments-vous-nourririez votre chiot mais pas vos enfants", etc.
- Alors, à quel moment l'utilisation d'un système
SecureString
devient-elle réellement pratique? - Cela vaut-il la peine de consacrer plus de temps au développement pour éliminer complètement l'utilisation d'un
System.String
objet? - Le but est-il
SecureString
simplement de réduire la quantité de temps qu'ilSystem.String
y a sur le tas (ce qui réduit son risque de passer à un fichier d'échange physique)? - Si un attaquant a déjà les moyens pour une inspection en tas, puis il le plus probable soit (A) a déjà les moyens de lire des séquences de touches, ou (B) déjà a physiquement la machine ... Alors serait l' aide d' un
SecureString
l'empêcher de se rendre à la données de toute façon? - Est-ce juste "la sécurité par l'obscurité"?
Désolé si je pose des questions trop épaisses, la curiosité a pris le dessus sur moi. N'hésitez pas à répondre à une ou toutes mes questions (ou dites-moi que mes hypothèses sont complètement fausses). :)
SecureString
n'est pas vraiment une chaîne sécurisée. C'est simplement un moyen de réduire la fenêtre de temps dans laquelle quelqu'un peut inspecter votre mémoire et obtenir avec succès les données sensibles. Ce n'est pas à l'épreuve des balles et ce n'était pas prévu. Mais les points que vous soulevez sont très valables. Connexe: stackoverflow.com/questions/14449579/…Réponses:
Il existe en fait des utilisations très pratiques de
SecureString
.Savez-vous combien de fois j'ai vu de tels scénarios? (la réponse est: beaucoup!):
RedGate
logiciel qui pouvait capturer la "valeur" des variables locales en cas d'exceptions, incroyablement utile. Cependant, je peux imaginer qu'il enregistrera les "mots de passe de chaîne" accidentellement.Savez-vous comment éviter tous ces problèmes?
SecureString
. Il s'assure généralement que vous ne faites pas d'erreurs stupides en tant que telles. Comment l'évite-t-il? En vous assurant que le mot de passe est chiffré dans la mémoire non gérée et que la valeur réelle n'est accessible que lorsque vous êtes sûr à 90% de ce que vous faites.En ce sens,
SecureString
fonctionne assez facilement:1) Tout est crypté
2) Appels des utilisateurs
AppendChar
3) Décryptez tout dans la MÉMOIRE NON GÉRÉE et ajoutez le personnage
4) Chiffrez tout à nouveau dans la MÉMOIRE NON GÉRÉE.
Que faire si l'utilisateur a accès à votre ordinateur? Un virus pourrait-il avoir accès à tous les virus
SecureStrings
? Oui. Tout ce que vous avez à faire est de vous connecterRtlEncryptMemory
lorsque la mémoire est décryptée, vous obtiendrez l'emplacement de l'adresse mémoire non cryptée et la lirez. Voila! En fait, vous pouvez créer un virus qui analysera en permanence l'utilisationSecureString
et enregistrera toutes les activités avec. Je ne dis pas que ce sera une tâche facile, mais cela peut être fait. Comme vous pouvez le voir, la "puissance" de aSecureString
complètement disparu une fois qu'il y a un utilisateur / virus dans votre système.Vous avez quelques points dans votre message. Bien sûr, si vous utilisez certains des contrôles de l'interface utilisateur qui contiennent un "mot de passe de chaîne" en interne, l'utilisation de réel
SecureString
n'est pas très utile. Cependant, il peut encore protéger contre une certaine stupidité que j'ai énumérée ci-dessus.En outre, comme d'autres l'ont noté, WPF prend en charge PasswordBox qui utilise en
SecureString
interne via sa propriété SecurePassword .L'essentiel est; si vous avez des données sensibles (mots de passe, cartes de crédit, ..), utilisez
SecureString
. C'est ce que le framework C # suit. Par exemple, laNetworkCredential
classe stocke le mot de passe sousSecureString
. Si vous regardez cela , vous pouvez voir plus de ~ 80 utilisations différentes dans le framework .NET deSecureString
.Il y a de nombreux cas où vous devez convertir
SecureString
en chaîne, car certaines API l'attendent.Le problème habituel est soit:
Vous avez soulevé un bon point: que se passe-t-il quand
SecureString
est convertistring
? Cela ne peut se produire qu'en raison du premier point. Par exemple, l'API ne sait pas que ce sont des données sensibles. Personnellement, je n'ai pas vu cela se produire. Extraire une chaîne de SecureString n'est pas si simple.Ce n'est pas simple pour une raison simple ; il n'a jamais été conçu pour permettre à l'utilisateur de convertir SecureString en chaîne, comme vous l'avez dit: GC se mettra en marche. Si vous vous voyez faire cela, vous devez prendre du recul et vous demander: pourquoi suis-je même en train de faire cela, ou ai-je vraiment besoin C'est pourquoi?
Il y a un cas intéressant que j'ai vu. À savoir, la fonction WinApi LogonUser prend LPTSTR comme mot de passe, ce qui signifie que vous devez appeler
SecureStringToGlobalAllocUnicode
. Cela vous donne essentiellement un mot de passe non chiffré qui réside dans la mémoire non gérée. Vous devez vous en débarrasser dès que vous avez terminé:Vous pouvez toujours étendre la
SecureString
classe avec une méthode d'extension, telle queToEncryptedString(__SERVER__PUBLIC_KEY)
, qui vous en donne unestring
instanceSecureString
chiffrée à l'aide de la clé publique du serveur. Seul le serveur peut alors le décrypter. Problème résolu: Garbage Collection ne verra jamais la chaîne "d'origine", car vous ne l'exposez jamais dans la mémoire gérée. C'est exactement ce qui se fait dansPSRemotingCryptoHelper
(EncryptSecureStringCore(SecureString secureString)
).Et comme quelque chose de très proche : Mono SecureString ne crypte pas du tout . L'implémentation a été commentée parce que ... attendez ... "Cela provoque en quelque sorte une rupture du test d'unité" , ce qui amène à mon dernier point:
SecureString
n'est pas pris en charge partout. Si la plateforme / l'architecture ne prend pas en chargeSecureString
, vous obtiendrez une exception. Il existe une liste de plates-formes prises en charge dans la documentation.la source
SecureString
serait beaucoup plus pratique s'il y avait un mécanisme pour accéder à leurs caractères individuels. L'efficacité d'un tel mécanisme pourrait être améliorée en ayant un type structSecureStringTempBuffer
sans aucun membre public, qui pourrait être passéref
à laSecureString
méthode "lire un caractère" [si le cryptage / décryptage est traité en blocs de 8 caractères, une telle structure pourrait contenir des données pour 8 caractères et l'emplacement du premier de ces caractères dansSecureString
].SecureString
il doit être utilisé tout au long de la pile.EngineSettings
votre méthode d'extension?SecureString
ne devrait pas être utilisée pour de nouveaux développements ?Il y a peu de problèmes dans vos hypothèses.
Tout d'abord, la classe SecureString n'a pas de constructeur String. Pour en créer un, vous allouez un objet, puis ajoutez les caractères.
Dans le cas d'une interface graphique ou d'une console, vous pouvez très facilement passer chaque touche enfoncée à une chaîne sécurisée.
La classe est conçue de manière à ce que vous ne puissiez pas, par erreur, accéder à la valeur stockée. Cela signifie que vous ne pouvez pas obtenir le
string
mot de passe directement à partir de celui-ci.Ainsi, pour l'utiliser, par exemple, pour vous authentifier via le Web, vous devrez utiliser des classes appropriées qui sont également sécurisées.
Dans le framework .NET, vous avez quelques classes qui peuvent utiliser SecureString
(plus)
Pour conclure, la classe SecureString peut être utile, mais nécessite plus d'attention de la part du développeur.
Tout cela, avec des exemples, est bien décrit dans la documentation MSDN de SecureString
la source
SecureString
sur le réseau sans le sérialiser en unstring
? Je pense que l'OP de la question est qu'il arrive un moment où vous voulez réellement utiliser la valeur conservée en toute sécurité dans unSecureString
, ce qui signifie que vous devez la retirer de là, et ce n'est plus sûr. Dans toute la bibliothèque de classes Framework, il n'y a pratiquement aucune méthode qui accepteSecureString
directement une entrée (pour autant que je puisse voir), alors quel est l'intérêt de conserver une valeur à l'intérieur de aSecureString
en premier lieu?char[]
et en l'envoyantchar
sur un socket - en ne créant aucun objet récupérable dans le processus.Un SecureString est utile si:
Vous le construisez caractère par caractère (par exemple à partir d'une entrée de console) ou l'obtenez à partir d'une API non gérée
Vous l'utilisez en le transmettant à une API non managée (SecureStringToBSTR).
Si jamais vous le convertissez en chaîne gérée, vous avez déjoué son objectif.
MISE À JOUR en réponse au commentaire
Une fois converti en BSTR, le composant non géré qui consomme le BSTR peut mettre à zéro la mémoire. La mémoire non gérée est plus sécurisée dans le sens où elle peut être réinitialisée de cette manière.
Cependant, il y a très peu d'API dans le .NET Framework qui prennent en charge SecureString, vous avez donc raison de dire que leur valeur est très limitée aujourd'hui.
Le cas d'utilisation principal que je verrais est dans une application cliente qui nécessite que l'utilisateur entre un code ou un mot de passe très sensible. L'entrée utilisateur peut être utilisée caractère par caractère pour créer une SecureString, puis elle peut être transmise à une API non gérée, qui met à zéro le BSTR qu'il reçoit après l'avoir utilisé. Tout vidage de mémoire ultérieur ne contiendra pas la chaîne sensible.
Dans une application serveur, il est difficile de voir où cela serait utile.
MISE À JOUR 2
Un exemple d'une API .NET qui accepte une SecureString est ce constructeur pour la classe X509Certificate . Si vous spelunk avec ILSpy ou similaire, vous verrez que SecureString est converti en interne en un tampon non géré (
Marshal.SecureStringToGlobalAllocUnicode
), qui est ensuite mis à zéro une fois terminé avec (Marshal.ZeroFreeGlobalAllocUnicode
).la source
SecureString
entrée, quelle serait leur utilisation? Vous devrez toujours vous reconvertirstring
tôt ou tard (ou,BSTR
comme vous le mentionnez, ce qui ne semble pas plus sûr). Alors, pourquoi s'en préoccuperSecureString
?Microsoft ne recommande pas d'utiliser
SecureString
pour les codes plus récents.À partir de la documentation de SecureString Class :
Qui recommande:
la source
Comme vous l'avez correctement identifié,
SecureString
offre un avantage spécifique par rapport àstring
: l'effacement déterministe. Il y a deux problèmes avec ce fait:SecureString
. Cela signifie que vous devez faire attention de ne jamais créer un GC-géré immuablestring
ou tout autre tampon qui stockera les informations sensibles (ou vous devrez garder une trace de ce aussi bien). En pratique, cela n'est pas toujours facile à réaliser, car de nombreuses API ne proposent qu'un moyen de travaillerstring
, nonSecureString
. Et même si vous parvenez à tout bien ...SecureString
protège contre des types d'attaques très spécifiques (et pour certains d'entre eux, ce n'est même pas si fiable). Par exemple,SecureString
cela vous permet de réduire la fenêtre de temps dans laquelle un attaquant peut vider la mémoire de votre processus et d'extraire avec succès les informations sensibles (encore une fois, comme vous l'avez correctement souligné), mais en espérant que la fenêtre est trop petite pour que l'attaquant puisse prendre un instantané de votre mémoire n'est pas du tout considéré comme de la sécurité.Alors, quand devriez-vous l'utiliser? Ce n'est que lorsque vous travaillez avec quelque chose qui peut vous permettre de travailler
SecureString
pour tous vos besoins et même dans ce cas, vous devez toujours garder à l'esprit que cela n'est sécurisé que dans des circonstances spécifiques.la source
Le texte ci-dessous est copié depuis l'analyseur de code statique HP Fortify
Résumé: La méthode PassString () dans PassGenerator.cs stocke les données sensibles de manière non sécurisée (c'est-à-dire en chaîne), ce qui permet d'extraire les données via l'inspection du tas.
Explication: Les données sensibles (telles que les mots de passe, les numéros de sécurité sociale, les numéros de carte de crédit, etc.) stockées en mémoire peuvent être divulguées si elles sont stockées dans un objet String géré. Les objets chaîne ne sont pas épinglés, le garbage collector peut donc déplacer ces objets à volonté et laisser plusieurs copies en mémoire. Ces objets ne sont pas chiffrés par défaut, donc toute personne capable de lire la mémoire du processus pourra voir le contenu. De plus, si la mémoire du processus est échangée sur le disque, le contenu non chiffré de la chaîne sera écrit dans un fichier d'échange. Enfin, comme les objets String sont immuables, la suppression de la valeur d'une chaîne de la mémoire ne peut être effectuée que par le garbage collector CLR. Le garbage collector n'est pas obligé de s'exécuter à moins que le CLR manque de mémoire, il n'y a donc aucune garantie quant au moment où le garbage collection aura lieu.
Recommandations: au lieu de stocker des données sensibles dans des objets comme Strings, stockez-les dans un objet SecureString. Chaque objet stocke à tout moment son contenu dans un format crypté en mémoire.
la source
Je voudrais aborder ce point:
Un attaquant peut ne pas avoir un accès complet à l'ordinateur et à l'application mais peut avoir les moyens d'accéder à certaines parties de la mémoire du processus. Elle est généralement causée par des bogues tels que des dépassements de tampon lorsque des entrées spécialement conçues peuvent entraîner l'application ou l'écrasement d'une partie de la mémoire.
HeartBleed fuite de mémoire
Prenez Heartbleed par exemple. Des requêtes spécialement construites peuvent amener le code à exposer des parties aléatoires de la mémoire du processus à l'attaquant. Un attaquant peut extraire des certificats SSL de la mémoire, mais la seule chose dont il a besoin est simplement d'utiliser une requête mal formée.
Dans le monde du code managé, les dépassements de tampon deviennent beaucoup moins souvent un problème. Et dans le cas de WinForms, les données sont déjà stockées de manière non sécurisée et vous ne pouvez rien y faire. Cela rend la protection
SecureString
pratiquement inutile.Cependant, l'interface graphique peut être programmée pour être utilisée
SecureString
, et dans ce cas, réduire la fenêtre de disponibilité des mots de passe dans la mémoire peut valoir la peine. Par exemple, PasswordBox.SecurePassword de WPF est de typeSecureString
.la source
Il y a quelque temps, j'ai dû créer une interface ac # contre une passerelle de paiement par carte de crédit java et il fallait un cryptage des clés de communication sécurisé compatible. Comme l'implémentation Java était assez spécifique et j'ai dû travailler avec les données protégées d'une manière donnée.
J'ai trouvé cette conception assez simple à utiliser et plus simple que de travailler avec SecureString… pour ceux qui aiment l'utiliser… n'hésitez pas, aucune restriction légale :-). Notez que ces classes sont internes, vous devrez peut-être les rendre publiques.
la source