मुझे लगता है कि स्मृति में डिक्रिप्टेड स्ट्रिंग पर बेहतर नियंत्रण के लिए एक अनाम फ़ंक्शन में अपने आश्रित तर्क SecureString
को संलग्न करना सबसे अच्छा होगा ।
इस स्निपेट में सिक्योरस्ट्रीम को डिक्रिप्ट करने के लिए कार्यान्वयन होगा:
- मेमोरी में स्ट्रिंग को पिन करें (जो कि आप करना चाहते हैं, लेकिन यहां अधिकांश उत्तरों से गायब प्रतीत होता है)।
- दर्रा इसके संदर्भ समारोह / कार्रवाई प्रतिनिधि को।
- इसे मेमोरी से स्क्रब करें और जीसी को
finally
ब्लॉक में छोड़ दें।
यह स्पष्ट रूप से "मानकीकृत" करना आसान बनाता है और कम वांछनीय विकल्पों पर भरोसा करने वाले कॉलर्स को बनाए रखता है:
- एक
string DecryptSecureString(...)
सहायक फ़ंक्शन से डिक्रिप्ट किए गए स्ट्रिंग को वापस करना।
- जहां भी जरूरत हो इस कोड को डुप्लिकेट करना।
यहां देखें, आपके पास दो विकल्प हैं:
static T DecryptSecureString<T>
जो आपको परिणाम का उपयोग करने की अनुमति देता है Func
कॉलर से प्रतिनिधि (जैसा कि DecryptSecureStringWithFunc
परीक्षण विधि में दिखाया गया है )।
static void DecryptSecureString
बस एक "शून्य" संस्करण है जो Action
उन मामलों में एक प्रतिनिधि को नियुक्त करता है जहां आप वास्तव में कुछ भी नहीं चाहते हैं / कुछ भी वापस करने की आवश्यकता नहीं है (जैसा कि बदले में दिखाया गया है)DecryptSecureStringWithAction
परीक्षण विधि )।
दोनों के लिए उदाहरण उपयोग में पाया जा सकता है StringsTest
शामिल वर्ग ।
Strings.cs
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace SecurityUtils
{
public partial class Strings
{
/// <summary>
/// Passes decrypted password String pinned in memory to Func delegate scrubbed on return.
/// </summary>
/// <typeparam name="T">Generic type returned by Func delegate</typeparam>
/// <param name="action">Func delegate which will receive the decrypted password pinned in memory as a String object</param>
/// <returns>Result of Func delegate</returns>
public static T DecryptSecureString<T>(SecureString secureString, Func<string, T> action)
{
var insecureStringPointer = IntPtr.Zero;
var insecureString = String.Empty;
var gcHandler = GCHandle.Alloc(insecureString, GCHandleType.Pinned);
try
{
insecureStringPointer = Marshal.SecureStringToGlobalAllocUnicode(secureString);
insecureString = Marshal.PtrToStringUni(insecureStringPointer);
return action(insecureString);
}
finally
{
//clear memory immediately - don't wait for garbage collector
fixed(char* ptr = insecureString )
{
for(int i = 0; i < insecureString.Length; i++)
{
ptr[i] = '\0';
}
}
insecureString = null;
gcHandler.Free();
Marshal.ZeroFreeGlobalAllocUnicode(insecureStringPointer);
}
}
/// <summary>
/// Runs DecryptSecureString with support for Action to leverage void return type
/// </summary>
/// <param name="secureString"></param>
/// <param name="action"></param>
public static void DecryptSecureString(SecureString secureString, Action<string> action)
{
DecryptSecureString<int>(secureString, (s) =>
{
action(s);
return 0;
});
}
}
}
StringsTest.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security;
namespace SecurityUtils.Test
{
[TestClass]
public class StringsTest
{
[TestMethod]
public void DecryptSecureStringWithFunc()
{
// Arrange
var secureString = new SecureString();
foreach (var c in "UserPassword123".ToCharArray())
secureString.AppendChar(c);
secureString.MakeReadOnly();
// Act
var result = Strings.DecryptSecureString<bool>(secureString, (password) =>
{
return password.Equals("UserPassword123");
});
// Assert
Assert.IsTrue(result);
}
[TestMethod]
public void DecryptSecureStringWithAction()
{
// Arrange
var secureString = new SecureString();
foreach (var c in "UserPassword123".ToCharArray())
secureString.AppendChar(c);
secureString.MakeReadOnly();
// Act
var result = false;
Strings.DecryptSecureString(secureString, (password) =>
{
result = password.Equals("UserPassword123");
});
// Assert
Assert.IsTrue(result);
}
}
}
जाहिर है, यह इस फ़ंक्शन के निम्नलिखित तरीके से दुरुपयोग को नहीं रोकता है, इसलिए बस ऐसा करने के लिए सावधान रहें:
[TestMethod]
public void DecryptSecureStringWithAction()
{
// Arrange
var secureString = new SecureString();
foreach (var c in "UserPassword123".ToCharArray())
secureString.AppendChar(c);
secureString.MakeReadOnly();
// Act
string copyPassword = null;
Strings.DecryptSecureString(secureString, (password) =>
{
copyPassword = password; // Please don't do this!
});
// Assert
Assert.IsNull(copyPassword); // Fails
}
हैप्पी कोडिंग!