Comment convertir SecureSsortingng en System.Ssortingng?

Toutes les réserves à propos de la non-sécurisation de votre SecureSsortingng en créant un System.Ssortingng à part , comment peut-on le faire?

Comment puis-je convertir un System.Security.SecureSsortingng ordinaire en System.Ssortingng?

Je suis sûr que beaucoup d’entre vous qui connaissez SecureSsortingng vont répondre que l’on ne devrait jamais transformer un SecureSsortingng en une chaîne .NET ordinaire, car cela supprime toutes les protections de sécurité. Je sais Mais pour le moment, mon programme fait tout de toute façon avec des chaînes ordinaires, et j’essaie d’améliorer sa sécurité et bien que je vais utiliser une API qui me renvoie une SecureSsortingng, je n’essaie pas de l’utiliser pour augmenter ma sécurité.

Je suis au courant de Marshal.SecureSsortingngToBSTR, mais je ne sais pas comment prendre ce BSTR et en faire un System.Ssortingng.

Pour ceux qui peuvent demander de savoir pourquoi je souhaiterais le faire, eh bien, je prends un mot de passe d’un utilisateur et le soumets sous la forme d’un fichier HTML POST pour connecter l’utilisateur à un site Web. Donc, cela doit être fait avec des tampons gérés et non chiffrés. Si je pouvais même accéder au tampon non géré et non crypté, j’imagine que je pourrais écrire des stream octet par octet sur le stream réseau et espérer que cela maintiendrait le mot de passe en sécurité dans son intégralité. J’espère une réponse à au moins un de ces scénarios.

Utilisez la classe System.Runtime.InteropServices.Marshal :

 Ssortingng SecureSsortingngToSsortingng(SecureSsortingng value) { IntPtr valuePtr = IntPtr.Zero; try { valuePtr = Marshal.SecureSsortingngToGlobalAllocUnicode(value); return Marshal.PtrToSsortingngUni(valuePtr); } finally { Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); } } 

Si vous souhaitez éviter de créer un object chaîne géré, vous pouvez accéder aux données brutes à l’aide de Marshal.ReadInt16(IntPtr, Int32) :

 void HandleSecureSsortingng(SecureSsortingng value) { IntPtr valuePtr = IntPtr.Zero; try { valuePtr = Marshal.SecureSsortingngToGlobalAllocUnicode(value); for (int i=0; i < value.Length; i++) { short unicodeChar = Marshal.ReadInt16(valuePtr, i*2); // handle unicodeChar } } finally { Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); } } 

De toute évidence, vous savez comment cela va à l’encontre du but de SecureSsortingng, mais je le reformule quand même.

Si vous voulez un one-liner, essayez ceci: (.NET 4 et supérieur uniquement)

 ssortingng password = new System.Net.NetworkCredential(ssortingng.Empty, securePassword).Password; 

Où securePassword est un SecureSsortingng.

Dang. juste après avoir posté ceci j’ai trouvé la réponse profondément dans cet article . Mais si quelqu’un sait comment accéder à la mémoire tampon non gérée et non chiffrée d’IntPtr que cette méthode expose, un octet à la fois, de sorte que je n’ai pas besoin de créer un object chaîne géré pour conserver une sécurité élevée, veuillez append une réponse. 🙂

 static Ssortingng SecureSsortingngToSsortingng(SecureSsortingng value) { IntPtr bstr = Marshal.SecureSsortingngToBSTR(value); try { return Marshal.PtrToSsortingngBSTR(bstr); } finally { Marshal.FreeBSTR(bstr); } } 

Je pense qu’il serait préférable que les fonctions dépendantes de SecureSsortingng encapsulent leur logique dépendante dans une fonction anonyme pour un meilleur contrôle de la chaîne déchiffrée en mémoire (une fois épinglée).

L’implémentation du déchiffrement de SecureSsortingngs dans cet extrait de code:

  1. Épinglez la chaîne en mémoire (ce que vous voulez faire mais qui semble manquer dans la plupart des réponses ici).
  2. Transmettez sa référence au délégué Func / Action.
  3. Frottez-le de la mémoire et libérez le GC dans le bloc finally .

Cela rend évidemment beaucoup plus facile la “standardisation” et le maintien des appelants plutôt que de recourir à des alternatives moins souhaitables:

  • Renvoyer la chaîne déchiffrée à partir d’une ssortingng DecryptSecureSsortingng(...) aide fonction ssortingng DecryptSecureSsortingng(...) .
  • Dupliquer ce code partout où il est nécessaire.

Remarquez ici, vous avez deux options:

  1. static T DecryptSecureSsortingng qui vous permet d’accéder au résultat du délégué Func partir de l’appelant (comme indiqué dans la méthode de test DecryptSecureSsortingngWithFunc ).
  2. static void DecryptSecureSsortingng est simplement une version “vide” qui emploie un délégué Action dans les cas où vous ne voulez / ne devez rien retourner (comme le montre la méthode de test DecryptSecureSsortingngWithAction ).

Des exemples d’utilisation pour les deux peuvent être trouvés dans la classe SsortingngsTest incluse.

Ssortingngs.cs

 using System; using System.Runtime.InteropServices; using System.Security; namespace SecurityUtils { public partial class Ssortingngs { ///  /// Passes decrypted password Ssortingng pinned in memory to Func delegate scrubbed on return. ///  /// Generic type returned by Func delegate /// Func delegate which will receive the decrypted password pinned in memory as a Ssortingng object /// Result of Func delegate public static T DecryptSecureSsortingng(SecureSsortingng secureSsortingng, Func action) { var insecureSsortingngPointer = IntPtr.Zero; var insecureSsortingng = Ssortingng.Empty; var gcHandler = GCHandle.Alloc(insecureSsortingng, GCHandleType.Pinned); try { insecureSsortingngPointer = Marshal.SecureSsortingngToGlobalAllocUnicode(secureSsortingng); insecureSsortingng = Marshal.PtrToSsortingngUni(insecureSsortingngPointer); return action(insecureSsortingng); } finally { insecureSsortingng = null; gcHandler.Free(); Marshal.ZeroFreeGlobalAllocUnicode(insecureSsortingngPointer); } } ///  /// Runs DecryptSecureSsortingng with support for Action to leverage void return type ///  ///  ///  public static void DecryptSecureSsortingng(SecureSsortingng secureSsortingng, Action action) { DecryptSecureSsortingng(secureSsortingng, (s) => { action(s); return 0; }); } } } 

SsortingngsTest.cs

 using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Security; namespace SecurityUtils.Test { [TestClass] public class SsortingngsTest { [TestMethod] public void DecryptSecureSsortingngWithFunc() { // Arrange var secureSsortingng = new SecureSsortingng(); foreach (var c in "UserPassword123".ToCharArray()) secureSsortingng.AppendChar(c); secureSsortingng.MakeReadOnly(); // Act var result = Ssortingngs.DecryptSecureSsortingng(secureSsortingng, (password) => { return password.Equals("UserPassword123"); }); // Assert Assert.IsTrue(result); } [TestMethod] public void DecryptSecureSsortingngWithAction() { // Arrange var secureSsortingng = new SecureSsortingng(); foreach (var c in "UserPassword123".ToCharArray()) secureSsortingng.AppendChar(c); secureSsortingng.MakeReadOnly(); // Act var result = false; Ssortingngs.DecryptSecureSsortingng(secureSsortingng, (password) => { result = password.Equals("UserPassword123"); }); // Assert Assert.IsTrue(result); } } } 

Evidemment, cela n’empêche pas les abus de cette fonction de la manière suivante, alors faites juste attention à ne pas faire ceci:

 [TestMethod] public void DecryptSecureSsortingngWithAction() { // Arrange var secureSsortingng = new SecureSsortingng(); foreach (var c in "UserPassword123".ToCharArray()) secureSsortingng.AppendChar(c); secureSsortingng.MakeReadOnly(); // Act ssortingng copyPassword = null; Ssortingngs.DecryptSecureSsortingng(secureSsortingng, (password) => { copyPassword = password; // Please don't do this! }); // Assert Assert.IsNull(copyPassword); // Fails } 

Heureux codage!

À mon avis, les méthodes d’extension sont le moyen le plus confortable de résoudre ce problème.

J’ai pris Steve dans l’ excellente réponse de CO et l’ai ajouté dans une classe d’extension comme suit, avec une seconde méthode que j’ai également ajoutée pour prendre en charge l’autre chaîne (ssortingng -> secure). une chaîne normale après:

 public static class Extensions { // convert a secure ssortingng into a normal plain text ssortingng public static Ssortingng ToPlainSsortingng(this System.Security.SecureSsortingng secureStr) { Ssortingng plainStr=new System.Net.NetworkCredential(ssortingng.Empty, secureStr).Password; return plainStr; } // convert a plain text ssortingng into a secure ssortingng public static System.Security.SecureSsortingng ToSecureSsortingng(this Ssortingng plainStr) { var secStr = new System.Security.SecureSsortingng(); secStr.Clear(); foreach (char c in plainStr.ToCharArray()) { secStr.AppendChar(c); } return secStr; } } 

Avec cela, vous pouvez maintenant simplement convertir vos chaînes comme vous le faites :

 // create a secure ssortingng System.Security.SecureSsortingng securePassword = "MyCleverPwd123".ToSecureSsortingng(); // convert it back to plain text Ssortingng plainPassword = securePassword.ToPlainSsortingng(); // convert back to normal ssortingng 

Mais gardez à l’esprit que la méthode de décodage ne doit être utilisée que pour les tests.

 // using so that Marshal doesn't have to be qualified using System.Runtime.InteropServices; //using for SecureSsortingng using System.Security; public ssortingng DecodeSecureSsortingng (SecureSsortingng Convert) { //convert to IntPtr using Marshal IntPtr cvttmpst = Marshal.SecureSsortingngToBSTR(Convert); //convert to ssortingng using Marshal ssortingng cvtPlainPassword = Marshal.PtrToSsortingngAuto(cvttmpst); //return the now plain ssortingng return cvtPlainPassword; } 

Si vous utilisez un SsortingngBuilder au lieu d’une ssortingng , vous pouvez remplacer la valeur réelle en mémoire lorsque vous avez terminé. De cette façon, le mot de passe ne restra pas en mémoire tant que la récupération de mémoire ne sera pas terminée.

 SsortingngBuilder.Append(plainTextPassword); SsortingngBuilder.Clear(); // overwrite with reasonably random characters SsortingngBuilder.Append(New Guid().ToSsortingng());