메모리에서 해독 된 문자열을 더 잘 제어 할 수 있도록 SecureString
종속 함수가 익명 함수로 종속 논리 를 캡슐화 하는 것이 가장 좋습니다 (한 번 고정됨).
이 스 니펫에서 SecureStrings를 해독하기위한 구현은 다음과 같습니다.
- 메모리에 문자열을 고정하십시오 (원하는 일이지만 여기 대부분의 답변에서 누락 된 것처럼 보입니다).
- 패스 의 참조 Func을 / 액션 위양합니다.
- 메모리에서 스크럽하고
finally
블록 에서 GC를 해제합니다 .
이렇게하면 덜 바람직한 대안에 의존하는 것보다 호출자를 "표준화"하고 유지 관리하는 것이 훨씬 쉬워집니다.
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
{
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
{
fixed(char* ptr = insecureString )
{
for(int i = 0; i < insecureString.Length; i++)
{
ptr[i] = '\0';
}
}
insecureString = null;
gcHandler.Free();
Marshal.ZeroFreeGlobalAllocUnicode(insecureStringPointer);
}
}
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()
{
var secureString = new SecureString();
foreach (var c in "UserPassword123".ToCharArray())
secureString.AppendChar(c);
secureString.MakeReadOnly();
var result = Strings.DecryptSecureString<bool>(secureString, (password) =>
{
return password.Equals("UserPassword123");
});
Assert.IsTrue(result);
}
[TestMethod]
public void DecryptSecureStringWithAction()
{
var secureString = new SecureString();
foreach (var c in "UserPassword123".ToCharArray())
secureString.AppendChar(c);
secureString.MakeReadOnly();
var result = false;
Strings.DecryptSecureString(secureString, (password) =>
{
result = password.Equals("UserPassword123");
});
Assert.IsTrue(result);
}
}
}
분명히 이것은 다음과 같은 방식으로이 함수의 남용을 방지하지 못하므로 이렇게하지 않도록주의하십시오.
[TestMethod]
public void DecryptSecureStringWithAction()
{
var secureString = new SecureString();
foreach (var c in "UserPassword123".ToCharArray())
secureString.AppendChar(c);
secureString.MakeReadOnly();
string copyPassword = null;
Strings.DecryptSecureString(secureString, (password) =>
{
copyPassword = password;
});
Assert.IsNull(copyPassword);
}
즐거운 코딩 되세요!