Programing

.NET에서 언제 SecureString이 필요합니까?

crosscheck 2020. 5. 19. 21:30
반응형

.NET에서 언제 SecureString이 필요합니까?


.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:

주요 목적은 공격 표면을 제거하는 것이 아니라 감소시키는 것입니다. SecureStrings가비지 콜렉터가 RAM을 이동하거나 복사하지 않습니다. 또한 일반 텍스트가 스왑 파일이나 코어 덤프에 기록되지 않도록합니다. 암호화는 난독 화와 비슷하며 해커를 막을 수는 없지만 암호화 및 해독에 사용되는 대칭 키 를 찾을 수 있습니다.

다른 사람들이 말했듯이 SecureString문자별로 문자 를 작성 해야하는 이유 는 그렇지 않은 첫 번째 명백한 결함 때문입니다. 아마도 비밀 값을 이미 일반 문자열로 가지고 있기 때문에 요점은 무엇입니까?

SecureStrings는 Chicken-and-Egg 문제를 해결하기위한 첫 번째 단계이므로, 대부분의 현재 시나리오에서이를 사용하기 위해 일반 문자열로 다시 변환해야하지만 프레임 워크에 존재하면 프레임 워크에 대한 지원이 향상됩니다. 미래-적어도 프로그램이 약한 링크가 될 필요가없는 지점까지.


편집 : SecureString을 사용하지 마십시오

현재 지침에 따르면 수업을 사용해서는 안됩니다. 자세한 내용은 다음 링크에서 확인할 수 있습니다 : https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

기사에서 :

DE0001 : SecureString을 사용하지 않아야합니다

자극

  • SecureString프로세스 메모리에 비밀을 일반 텍스트로 저장하지 않도록 하는 것이 목적입니다 .
  • 그러나 Windows에서도 SecureStringOS 개념으로 존재하지 않습니다.
    • 그것은 단지 일반 텍스트를 점점 짧게 만듭니다; .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 의 요점입니다 .

긴 답변

The reason SecureString exists is because you cannot use ZeroMemory to wipe sensitive data when you're done with it. It exists to solve an issue that exists because of the CLR.

In a regular native application you would call SecureZeroMemory:

Fills a block of memory with zeros.

Note: SecureZeroMemory is is identical to ZeroMemory, except the compiler won't optimize it away.

The problem is that you can't call ZeroMemory or SecureZeroMemory inside .NET. And in .NET strings are immutable; you can't even overwrite the contents of the string like you can do in other languages:

//Wipe out the password
for (int i=0; i<password.Length; i++)
   password[i] = \0;

So what can you do? How do we provide the ability in .NET to wipe a password, or credit card number from memory when we're done with it?

The only way it can be done would be to place the string in some native memory block, where you can then call ZeroMemory. A native memory object such as:

  • a BSTR
  • an HGLOBAL
  • CoTaskMem unmanaged memory

SecureString gives the lost ability back

In .NET, Strings cannot be wiped when you are done with them:

  • they are immutable; you cannot overwrite their contents
  • you cannot Dispose of them
  • their cleanup is at the mercy of the garbage collector

SecureString exists as a way to pass around strings safety, and be able to guarantee their cleanup when you need to.

You asked the question:

why can't I just say:

SecureString password = new SecureString("password");

Because now you have password in memory; with no way to wipe it. It's stuck there until the CLR happens to decide to re-use that memory. You've put us right back where we started; a running application with a password we can't get rid of, and where a memory dump (or Process Monitor) can see the password.

SecureString uses the Data Protection API to store the string encrypted in memory; that way the string will not exist in swapfiles, crash dumps, or even in the local variables window with a colleague looking over your should.

How do i read the password?

Then is the question: how do i interact with the string? You absolutely don't want a method like:

String connectionString = secureConnectionString.ToString()

because now you're right back where you started - a password you cannot get rid of. You want to force developers to handle the sensitive string correctly - so that it can be wiped from memory.

That is why .NET provides three handy helper functions to marshall a SecureString into a unmanaged memory:

You convert the string into an unmanaged memory blob, handle it, and then wipe it again.

Some APIs accept SecureStrings. For example in ADO.net 4.5 the SqlConnection.Credential takes a set SqlCredential:

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

You can also change the password within a Connection String:

SqlConnection.ChangePassword(connectionString, cred, newPassword);

And there are a lot of places inside .NET where they continue to accept a plain String for compatibility purposes, then quickly turn around an put it into a SecureString.

How to put text into the SecureString?

This still leaves the problem:

How do i get a password into the SecureString in the first place?

This is the challenge, but the point is to get you thinking about security.

Sometimes the functionality is already provided for you. For example, the WPF PasswordBox control can return you the entered password as a SecureString directly:

PasswordBox.SecurePassword Property

Gets the password currently held by the PasswordBox as a SecureString.

This is helpful because everywhere you used to pass around a raw string, you now have the type system complaining that SecureString is incompatible with String. You want to go as long as possible before having to convert your SecureString back into regular string.

Converting a SecureString is easy enough:

  • SecureStringToBSTR
  • PtrToStringBSTR

as in:

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;
}

They just really don't want you doing it.

But how do i get a string into a SecureString? Well what you need to do is stop having a password in a String in the first place. You needed to have it in something else. Even a Char[] array would be helpful.

That's when you can append each character and wipe the plaintext when you're done:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

You need your password stored in some memory that you can wipe. Load it into the SecureString from there.


tl;dr: SecureString exists to provide the equivalent of ZeroMemory.

Some people don't see the point in wiping the user's password from memory when a device is locked, or wiping wiping keystrokes from memory after they'authenticated. Those people do not use SecureString.


There are very few scenarios where you can sensibly use SecureString in the current version of the Framework. It's really only useful for interacting with unmanaged APIs - you can marshal it using Marshal.SecureStringToGlobalAllocUnicode.

As soon as you convert it to/from a System.String, you've defeated its purpose.

The MSDN sample generates the SecureString a character at a time from console input and passes the secure string to an unmanaged API. It's rather convoluted and unrealistic.

You might expect future versions of .NET to have more support for SecureString that will make it more useful, e.g.:

  • SecureString Console.ReadLineSecure() or similar to read console input into a SecureString without all the convoluted code in the sample.

  • WinForms TextBox replacement that stores its TextBox.Text property as a secure string so that passwords can be entered securely.

  • Extensions to security-related APIs to allow passwords to be passed as SecureString.

Without the above, SecureString will be of limited value.


I believe the reason why you have to do character appending instead of one flat instantiation is because in the background passing "password" to the constructor of SecureString puts that "password" string in memory defeating the purpose of secure string.

By appending you are only putting a character at a time into memory which is likley not to be adjacent to each other physically making it much harder to reconstruct the original string. I could be wrong here but that's how it was explained to me.

The purpose of the class is to prevent secure data from being exposed via a memory dump or similar tool.


MS found that on certain instances of causing the server (desktop, whatever) to crash there were times when the runtime environment would do a memory dump exposing the contents of what's in memory. Secure String encrypts it in memory to prevent the attacker from being able to retrieve the contents of the string.


One of the big benefits of a SecureString is that it is supposed avoid the possibility of your data being stored to disk due to page caching. If you have a password in memory and then load a large program or data set, your password may get written to the swap file as your program is paged out of memory. With a SecureString, at least the data will not be sitting around indefinitely on your disk in clear text.


I guess it's because the string is meant to be secure, i.e. a hacker should not be able to read it. If you initialize it with a string, the hacker could read the original string.


Well, as the description states, the value is stored encrypted, with means that a memory dump of your process won't reveal the string's value (without some fairly serious work).

The reason you can't just construct a SecureString from a constant string is because then you would have an unencrypted version of the string in memory. Limiting you to creating the string in pieces reduces the risk of having the whole string in memory at once.


Another use case is when you are working with payment applications (POS) and you simply can't use immutable data structures in order to store sensitive data because you are careful developer. For instance: if I will store sensitive card data or authorisation metadata into immutable string there always would be the case when this data will be available in memory for significant amount of time after it was discarded. I cannot simply overwrite it. Another huge advantage where such sensitive data being kept in memory encrypted.

참고URL : https://stackoverflow.com/questions/141203/when-would-i-need-a-securestring-in-net

반응형