.NET의 SecureString의 목적을 파악하려고합니다. MSDN에서 :
System.String 클래스의 인스턴스는 변경할 수 없으며 더 이상 필요하지 않은 경우 가비지 수집을 위해 프로그래밍 방식으로 예약 할 수 없습니다. 즉, 인스턴스는 작성된 후 읽기 전용이며 인스턴스가 컴퓨터 메모리에서 삭제 될시기를 예측할 수 없습니다. 따라서 String 개체에 암호, 신용 카드 번호 또는 개인 데이터와 같은 중요한 정보가 포함 된 경우, 응용 프로그램이 컴퓨터 메모리에서 데이터를 삭제할 수 없기 때문에 사용 후 정보가 노출 될 위험이 있습니다.
SecureString 개체는 텍스트 값이 있다는 점에서 String 개체와 유사합니다. 그러나 SecureString 개체의 값은 자동으로 암호화되어 응용 프로그램이 읽기 전용으로 표시 될 때까지 수정 될 수 있으며 응용 프로그램이나 .NET Framework 가비지 수집기에 의해 컴퓨터 메모리에서 삭제할 수 있습니다.
SecureString 인스턴스의 값은 인스턴스가 초기화되거나 값이 수정 될 때 자동으로 암호화됩니다. 애플리케이션은 MakeReadOnly 메소드를 호출하여 인스턴스를 변경할 수 없게하고 추가 수정을 방지 할 수 있습니다.
자동 암호화가 큰 보상입니까?
그리고 왜 내가 말할 수는 없습니다.
SecureString password = new SecureString("password");
대신에
SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
pass.AppendChar(c);
SecureString의 어떤 측면이 누락 되었습니까?
답변
SecureString 사용을 중단합니다. PG 사람들이 지원을 중단하는 것 같습니다. https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring 미래에도 가능할 것입니다 .
.NET Core의 모든 플랫폼에서 SecureString에서 암호화를 제거해야합니다.-SecureString을 폐기해야합니다. .NET Core에서 SecureString을 노출하지 않아야합니다.
답변
현재 사용하고있는 프레임 워크의 일부 SecureString
:
- WPF의
System.Windows.Controls.PasswordBox
제어는 암호를 내부적으로 SecureString으로 유지합니다 (복사본으로 노출됨PasswordBox::SecurePassword
) - 본
System.Diagnostics.ProcessStartInfo::Password
숙소는SecureString
- 의 생성자 는 비밀번호 를
X509Certificate2
가져옵니다.SecureString
주요 목적은 공격 표면을 제거하는 것이 아니라 감소시키는 것입니다. SecureStrings
가비지 콜렉터가 RAM을 이동하거나 복사하지 않습니다. 또한 일반 텍스트가 스왑 파일이나 코어 덤프에 기록되지 않도록합니다. 암호화는 난독 화와 비슷하며 해커를 막을 수는 없지만 암호화 및 해독에 사용되는 대칭 키 를 찾을 수 있습니다.
다른 사람들이 말했듯이 SecureString
문자별로 문자 를 작성 해야하는 이유 는 그렇지 않은 첫 번째 명백한 결함 때문입니다. 아마도 비밀 값을 이미 일반 문자열로 가지고 있기 때문에 요점은 무엇입니까?
SecureString
s는 Chicken-and-Egg 문제를 해결하는 첫 번째 단계이므로, 대부분의 현재 시나리오에서는이를 사용하기 위해 일반 문자열로 다시 변환해야하지만 프레임 워크에서의 존재는 이제 미래-적어도 프로그램이 약한 링크가 될 필요가없는 지점까지.
답변
편집 : SecureString을 사용하지 마십시오
현재 지침에 따르면 수업을 사용해서는 안됩니다. 자세한 내용은 다음 링크에서 확인할 수 있습니다. https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
기사에서 :
DE0001 : SecureString을 사용하지 않아야합니다
자극
SecureString
프로세스 메모리에 비밀을 일반 텍스트로 저장하지 않도록 하는 것이 목적입니다 .- 그러나 Windows에서도
SecureString
OS 개념으로 존재하지 않습니다.- 그것은 단지 일반 텍스트를 점점 짧게 만듭니다; .NET은 여전히 문자열을 일반 텍스트 표현으로 변환해야하기 때문에 완전히 막을 수는 없습니다.
- 이점은 일반 텍스트 표현이 인스턴스의 역할을하지 않는다는 것
System.String
입니다. 기본 버퍼의 수명이 짧습니다.
- 배열의 내용은 .NET Framework를 제외하고 암호화되지 않습니다.
- .NET Framework에서 내부 문자 배열의 내용은 암호화됩니다. .NET은 API 누락 또는 키 관리 문제로 인해 모든 환경에서 암호화를 지원하지 않습니다.
추천
SecureString
새로운 코드 에는 사용하지 마십시오 . 코드를 .NET Core로 포팅 할 때 배열의 내용이 메모리에 암호화되어 있지 않은 것을 고려하십시오.
자격 증명을 처리하는 일반적인 방법은 자격 증명을 피하고 대신 인증서 또는 Windows 인증과 같은 다른 인증 방법을 사용하는 것입니다.
편집 종료 : 아래의 원본 요약
많은 훌륭한 답변; 다음은 논의 된 내용에 대한 간략한 개요입니다.
Microsoft는 신용 카드, 암호 등의 중요한 정보로 더 나은 보안을 제공하기 위해 SecureString 클래스를 구현했습니다. 자동으로 다음을 제공합니다.
- 암호화 (메모리 덤프 또는 페이지 캐싱의 경우)
- 메모리에 고정
- 읽기 전용으로 표시하는 기능 (추가 수정 방지)
- 상수 문자열을 전달하지 않도록하여 안전한 구조
현재 SecureString은 사용이 제한되어 있지만 앞으로 더 나은 채택을 기대합니다.
이 정보를 기반으로 SecureString의 생성자는 문자열을 가져 와서 문자 배열로 슬라이스하지 않아야합니다.
추가 정보:
- .NET 보안 블로그 의 게시물 은 여기에서 다루는 것과 거의 동일합니다.
- 또 다른 사람은
그것을 다시 방문하고 SecureString의 내용을 덤프 할 수있는 도구를 언급했습니다.
편집 : 많은 사람들에게 좋은 정보가 있기 때문에 최상의 답변을 선택하기가 어렵다는 것을 알았습니다. 너무 나빠서 보조 답변 옵션이 없습니다.
답변
짧은 답변
왜 난 그냥 말할 수 없습니다 :
SecureString password = new SecureString("password");
지금 당신은 password
메모리에 있기 때문에 ; 그것을 닦을 방법이 없습니다-정확히 요점입니다. SecureString .
긴 답변
SecureString 이 존재 하는 이유 는 중요한 데이터를 다룰 때 ZeroMemory 를 사용 하여 중요한 데이터를 지울 수 없기 때문 입니다. 존재하는 문제를 해결하기 위해 존재합니다 .CLR로 .
일반 네이티브 응용 프로그램에서는 다음을 호출합니다 SecureZeroMemory
.
메모리 블록을 0으로 채 웁니다.
참고 : SecureZeroMemory이다는 동일 ZeroMemory
, 컴파일러를 제외하고 멀리 최적화되지 않습니다.
문제는 전화를 걸 거나 .NET 내부에서 할 수 없다는 것 입니다. 그리고 .NET에서 문자열은 변경할 수 없습니다. 다른 언어에서와 같이 문자열의 내용을 덮어 쓸 수도 없습니다 .ZeroMemory
SecureZeroMemory
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
그래서 당신은 무엇을 할 수 있습니까? .NET에서 암호 나 신용 카드 번호를 메모리에서 지울 수있는 기능을 어떻게 제공합니까?
그것을 할 수있는 유일한 방법은 일부 문자열을 배치하는 것입니다 네이티브 는 메모리 블록, 수 후 전화 ZeroMemory
. 다음과 같은 기본 메모리 객체 :
- BSTR
- HGLOBAL
- CoTaskMem 비 관리 메모리
SecureString은 잃어버린 능력을 돌려줍니다.
.NET에서 문자열을 완료하면 문자열을 지울 수 없습니다.
- 그들은 불변이다. 당신은 그들의 내용을 덮어 쓸 수 없습니다
- 당신
Dispose
은 그들 중 누구도 - 그들의 청소는 가비지 수집기의 자비에 있습니다
SecureString은 문자열 안전을 전달하는 방법으로 존재하며 필요할 때 정리를 보장 할 수 있습니다.
당신은 질문을했다 :
왜 난 그냥 말할 수 없습니다 :
SecureString password = new SecureString("password");
지금 당신은 password
메모리에 있기 때문에 ; 닦을 방법이 없습니다. CLR이 해당 메모리를 재사용하기로 결정할 때까지 중단됩니다. 당신은 우리가 시작한 곳으로 우리를 바로 돌려 놓았습니다. 우리가 제거 할 수없는 암호가있는 실행중인 응용 프로그램과 메모리 덤프 (또는 프로세스 모니터)가 암호를 볼 수있는 곳.
SecureString은 Data Protection API를 사용하여 메모리에 암호화 된 문자열을 저장합니다. 그런 식으로 스왑 파일, 크래시 덤프 또는 로컬 변수 창에 문자열이 존재하지 않아야합니다.
비밀번호는 어떻게 읽습니까?
그렇다면 질문은 : 문자열과 어떻게 상호 작용합니까? 당신은 절대적으로 다음 과 같은 방법을 원하지 않습니다 :
String connectionString = secureConnectionString.ToString()
이제 시작한 곳으로 바로 돌아갈 수 있기 때문에 제거 할 수없는 비밀번호입니다. 당신은 할 강제 제대로 민감한 문자열을 처리하기 위해 개발자 – 너무 것을 할 수 메모리에서 닦아.
따라서 .NET은 SecureString을 관리되지 않는 메모리에 마샬링하는 세 가지 편리한 도우미 함수를 제공합니다.
- SecureStringToBSTR ( ZeroFreeCoTaskMemUnicode로 해제 )
- SecureStringToCoTaskMemUnicode ( ZeroFreeCoTaskMemUnicode로 해제 )
- SecureStringToGlobalAllocUnicode ( ZeroFreeGlobalAllocUnicode로 해제 )
문자열을 관리되지 않는 메모리 얼룩으로 변환하고 처리 한 다음 다시 지 웁니다.
일부 API는 SecureStrings를 허용 합니다. 예를 들어 ADO.net 4.5에서 SqlConnection.Credential 은 SqlCredential 세트를 가져옵니다 .
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
연결 문자열 내에서 비밀번호를 변경할 수도 있습니다.
SqlConnection.ChangePassword(connectionString, cred, newPassword);
그리고 .NET 내부에는 호환성을 위해 일반 문자열을 계속 수용 한 다음 SecureString으로 빠르게 전환합니다.
SecureString에 텍스트를 넣는 방법?
여전히 문제가 남아 있습니다.
처음에 SecureString에 비밀번호를 얻으려면 어떻게해야합니까?
이것은 도전이지만, 요점은 보안에 대해 생각하게하는 것입니다.
때로는 기능이 이미 제공되어 있습니다. 예를 들어, WPF PasswordBox 컨트롤은 입력 한 암호를 SecureString으로 직접 반환 할 수 있습니다.
PasswordBox.SecurePassword 속성
PasswordBox가 현재 보유하고있는 비밀번호 를 SecureString 으로 가져옵니다 .
이것은 원시 문자열을 전달하는 데 사용되는 모든 곳에서 SecureString이 String과 호환되지 않는다고 불평하는 유형 시스템을 가지고 있기 때문에 유용합니다. SecureString을 다시 일반 문자열로 변환하기 전에 가능한 한 오래 가고 싶습니다.
SecureString 변환은 충분히 쉽습니다.
- SecureStringToBSTR
- PtrToStringBSTR
에서와 같이 :
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;
}
그들은 단지 당신이 그것을하고 싶지 않습니다.
그러나 SecureString에 문자열을 어떻게 가져 옵니까? 글쎄, 당신이해야 할 일은 처음에 문자열 에 암호를 갖는 것을 멈추는 것입니다. 당신은 다른 것을 가지고 있어야했습니다 . 심지어Char[]
배열 도움이 될 것입니다.
각 문자를 추가 할 수 있습니다 때이다 그리고 이 완료되면 일반 텍스트를 닦아 :
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
초기화 할 수 있는 일부 메모리에 비밀번호가 저장되어 있어야합니다 . 거기에서 SecureString에로드하십시오.
tl; dr : SecureString 은 ZeroMemory 와 동등한 기능을 제공합니다. .
어떤 사람들은에 지점이 표시되지 않는 장치가 잠겨있을 때 메모리에서 사용자의 암호를 닦아 , 또는 닦아 they’authenticated 후 메모리에서 닦아 키 입력을 . 그 사람들은 SecureString을 사용하지 않습니다.
답변
현재 버전의 프레임 워크에서 SecureString을 현명하게 사용할 수있는 시나리오는 거의 없습니다. 관리되지 않는 API와의 상호 작용에만 유용합니다. Marshal.SecureStringToGlobalAllocUnicode를 사용하여 마샬링 할 수 있습니다.
System.String으로 /에서 변환하자마자 그 목적을 잃었습니다.
MSDN 샘플 은 콘솔 입력에서 한 번에 한 문자 씩 SecureString을 생성하고 보안 문자열을 관리되지 않는 API로 전달합니다. 오히려 복잡하고 비현실적입니다.
향후 버전의 .NET은 SecureString을 더 많이 지원하여보다 유용하게 사용할 수 있습니다. 예를 들면 다음과 같습니다.
-
SecureString Console.ReadLineSecure () 또는 샘플에서 모든 복잡한 코드없이 SecureString으로 콘솔 입력을 읽는 것과 유사합니다.
-
암호를 안전하게 입력 할 수 있도록 TextBox.Text 속성을 보안 문자열로 저장하는 WinForms TextBox 대체.
-
비밀번호를 SecureString으로 전달할 수있는 보안 관련 API의 확장.
위의 내용이 없으면 SecureString의 값이 제한됩니다.
답변
플랫 인스턴스화 대신 문자를 추가 해야하는 이유는 SecureString의 생성자에 “password”를 전달하는 배경에서 “password”문자열을 메모리에 넣어 보안 문자열의 목적을 무효화하기 때문입니다.
덧붙여서 당신은 한 번에 한 문자 만 메모리에 두어 서로 인접하지 않기 때문에 원래의 문자열을 재구성하기가 훨씬 어려워집니다. 나는 여기에 틀릴 수 있지만 그것이 나에게 설명 된 방법입니다.
이 클래스의 목적은 메모리 덤프 또는 유사한 도구를 통해 보안 데이터가 노출되지 않도록하는 것입니다.
답변
MS는 서버 (데스크톱 등)가 충돌하는 특정 인스턴스에서 런타임 환경이 메모리에있는 내용의 내용을 노출시키는 메모리 덤프를 수행 할 때가 있음을 발견했습니다. 보안 문자열은 공격자가 문자열의 내용을 검색 할 수 없도록 메모리에 암호화합니다.