2008-09-29 6 views
7

내가 작업중인 프로그램에 대한 기능 요청 중 하나는 사용자가 입력 한 자격 증명 목록을 저장할 수 있기 때문에 공유 할 수 있다는 것입니다. 이 요청에 영감을 얻은 사례는 대규모 기업 네트워크에서 우리 프로그램을 사용하는 것이 었습니다. 상당히 복잡한 LAN으로 구성된 꽤 좋은 LAN으로 구성되었습니다. 아이디어는 우리의 프로그램이 다운되었을 때 WAN에 맞서기보다 엄격하게 관리되는 자격 증명이 포함 된 '구성'파일을 보내고 각 LAN에서 실행하고 결과를 압축하여 전자 메일로 보내는 것입니다 뒤로.SecureString 저장하기

예.

내 초기 본능은이 요청을 비웃는 것입니다 - 암호를 저장 하시겠습니까? 정말요? 그리고 확실하게 회사의 네트워크 부서는 그들이 가지고있는 WAN 제품을 시도하고 판매하는 것을 선호 할 것입니다. 그러나 자격 증명을 사용하는 클래스 중 하나가 SecureString을 사용할 수 있다는 것을 알게되고, 항상주의해야합니다. 당신은 사람들에게 어떤 노력을 덜어 줄 수있는 길을 찾았습니다. 저에게 궁금한 걸 갖게했습니다 :

민감한 데이터를 파일에 저장하고 다른 곳에서 열 수 있도록 암호화 된 SecureString을 저장할 수 있습니까?

당신의 생각은 무엇입니까, Stack Overflow?

+0

"네트워크 장애시 공유"를 어떻게 의미합니까? 제발 좀 더 자세히 설명해 주실 수 있습니까? –

답변

5

SecureString에 저장 지원이 없으며, 메모리 내 관리 문자열을 보호하기위한 메커니즘으로, 관리되지 않는 API와의 인터페이스에만 사용됩니다. 암호가 System.String 인스턴스에 저장된 경우 System.String의 특성으로 인해 보안이 떨어집니다. 가비지 수집 및 내부 처리의 존재는 필요할 때보 다 암호를 메모리에 더 오래 보관합니다. 또한 .NET 용 훌륭한 디버깅 도구로 인해 수명이 길지 않아도 리플렉션 또는 다른 .NET API를 통해 문자열에 액세스하는 것이 훨씬 쉬울 것입니다.

암호를 디스크에 저장하면 보안이 상당히 손상됩니다. 누군가 시스템에 물리적으로 액세스하거나 관리자 수준의 원격 액세스 권한을 가진 경우 수행 할 수있는 최선의 방법은 더 어렵지 만 불가능한 일은 아닙니다. 암호화 API를 사용하여 안전한 위치에 저장하고 액세스 권한을 구성하십시오.

메르세우스 (Merus), 나는 당신이 전체적인 시스템을 개선하려고 노력할 것을 제안합니다. 왜냐하면 당신이 설명하는 것처럼 (유익하다고 가정 할 때) 당신은 해쉬를 저장하는 것이 더 낫습니다. 실제 암호.

+1

나는 SecureString이 나를 위해 해시를 해주기를 바랬다. 나는 내 자신의 해쉬 함수를 롤백하는 것보다 낫다. – Merus

+1

PowerShell에서 C#을 사용하여 SecureString을 절약 할 수 있습니까? ?? http://stackoverflow.com/questions/11174425/how-does-one-securely-handle-passwords-in-a-custom-written-powershell-cmdlet – Kiquenet

3

SecureString의 암호화 된 바이트를 저장한다는 의미라면 SecureString의 키는 사용자와 프로세스에 연결됩니다. 다른 프로세스 나 다른 사용자의 해당 바이트를 읽으면 문자열을 해독 할 방법이 없습니다.

1

IsolatedStorageFileStream class을 살펴볼 수 있습니다. 어셈블리에서 액세스 할 수있는 파일 데이터를 쓰고 저장하는 방법을 지정합니다.

저는 SecureString을 사용할 수 있다고 생각하지 않습니다. 방금 전달 된 시리얼 (이진, XML 등)

당신은 또한 단지 예를 들어, 액세스 할 수의 일부를 저장할 수 있도록

1

SecureString는 직렬화되지 않습니다 그와 같은 것이 없기 때문에 securestring 객체의 "Password"속성. 마샬링을 사용하고 약간의 배관 작업을해야합니다. 사용자 자격 증명을 어딘가에 저장하려면 나중의 개발이 쉬워 지므로 직접 암호화하는 것이 좋습니다. SecureString 접근법을 평가 한 후에 우리는 스스로 무언가를 구현하기로 결정했으나 이것은 단지 2 센트에 불과합니다.

3

이렇게하면 메모리에 상주하는 SecureString의 포인트가 무력화됩니다. 따라서 파일에 저장하는 경우 더 이상 "안전하지"않으므로 일반 문자열로 저장할 수도 있습니다.

4

암호 해시를 비교하는 것이 좋습니다.
당신은 username과 아마도 다른 상수로 구성된 소금을 가지고 문자열 뒤에옵니다. 그런 다음 SHA1 *과 같은 해시 알고리즘에 전달합니다.
예를 들어 ,

using System.Security.Cryptography; 

public byte[] GetPasswordHash(string username, string password, string salt) 
{ 
    // get salted byte[] buffer, containing username, password and some (constant) salt 
    byte[] buffer; 
    using (MemoryStream stream = new MemoryStream()) 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     writer.Write(salt); 
     writer.Write(username); 
     writer.Write(password); 
     writer.Flush(); 

     buffer = stream.ToArray(); 
    } 

    // create a hash 
    SHA1 sha1 = SHA1.Create(); 
    return sha1.ComputeHash(buffer); 
} 

그런 다음 GetPasswordHash(username, givenPassword, salt)GetPasswordHash(username, expectedPassword, salt)에 대한 결과를 비교하는 것입니다.
사용자 이름과 비밀번호로 사용자 목록을 구현하는 경우 해시 (GetPasswordHash(username, givenPassword, salt)) 만 저장하고 저장된 해시와 비교하는 것을 고려할 수 있습니다.

+0

가끔은 주어진 암호를 비교하는 것이 아니라 프로그램 자체가 원하는 것입니다. 암호를 사용하여 다른 시스템에서 권한을 얻는 것. 메일 클라이언트와 마찬가지로 SMTP 서버에서 권한을 얻으려면 비밀번호를 사용하십시오. 그 상황에서 우리는 무엇을 할 수 있습니까? –

+0

@Sankaran : 각각의 경우에는 자체 솔루션이 있습니다. 대부분의 최신 API는 이미 암호 해시를 허용합니다. 일부에는 API 키가 있으므로 비밀번호의 해시를 알 필요조차 없습니다. 직접 암호 만 사용하도록 지원하는 이전 API를 사용하려면 암호 자체를 저장할 수밖에 없습니다. 이 경우, 일종의 암호화를 사용 하겠지만 꽤 쓸모가 없습니다. – configurator

+0

MD5는 해시 알고리즘 선택에 전혀 부적합합니다. bcrypt 또는 scrypt가 필요하거나 _least_ sha1에 있어야합니다 (심지어 권장하지도 않습니다). –

0

여기에 언급 된 것처럼 SecureString은이 시나리오에서 사용하는 최선의 방법은 아닙니다. 당신이 안전 만 암호의 표현을 공유 할 수 있도록, + 소금 암호을하지 내가 사용자의 자격 증명을 공유 할 필요가 있다면

나는 아마 이름를 공유하는 것와 해시 그것은 내용입니다.

이것에 단순히 방법은 예를 들어 BCryt 도서관 (where there's a .NET representation of it)를 사용하여 간단하게이 당신이 그것을 사용하는 것이 방법이다

을 공유 할 준비가 테이블에 사용자 이름과 암호를 표현 개최된다

를 클라이언트 끝에
StringBuilder sb = new StringBuilder(); 

// run ADO.NET/Entity Framework/etc and query your DB with something like: 
"SELECT user_id, username, password FROM [TblUsers];" 

// loop through the results 

sb.AppendFormat(
     "INSERT INTO [TblSharedUsers] SELECT '{0}','{1}','{2}'",    
      dr["id"], dr["username"], 
      BCrypt.HashPassword(dr["password"], BCrypt.GenerateSalt(12)); 
     ); 

// then run sb.ToSTring() agains your db 

, 당신이 만들 수있는 새로운 AuthenticationProviderTblSharedUsers에서 읽 및 사용자 암호를 확인합니다 (네트워크가 IoCDI를 사용하여 사용할 수 없을 때 쉽게 변경할 수 있도록) like

string userPassword = Request["password"]; 

"SELECT id, password FROM [TblSharedUsers] WHERE username = @usr;" 

if(BCrypt.CheckPassword(userPassword, dr["password"])) 
    // User can log in 
else 
    // Credentials are invalid 

나는 이것이 동일한 문제를 가진 사람을 돕기를 바랍니다.