Resposta curta
por que não posso apenas dizer:
SecureString password = new SecureString("password");
Porque agora você tem password
na memória; sem nenhuma maneira de limpá-lo - que é exatamente o ponto do SecureString .
Resposta longa
O motivo da existência do SecureString é que você não pode usar o ZeroMemory para limpar dados confidenciais quando terminar. Existe para resolver um problema que existe devido ao CLR.
Em um aplicativo nativo comum , você chamaria SecureZeroMemory
:
Preenche um bloco de memória com zeros.
Nota : SecureZeroMemory is é idêntico a ZeroMemory
, exceto pelo compilador que não será otimizado.
O problema é que você não pode ligar ZeroMemory
ou SecureZeroMemory
dentro do .NET. E no .NET as strings são imutáveis; você não pode nem substituir o conteúdo da string como em outros idiomas:
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
Então o que você pode fazer? Como fornecemos a capacidade do .NET de limpar uma senha ou número de cartão de crédito da memória quando terminamos?
A única maneira de fazer isso seria colocar a string em algum bloco de memória nativo , onde você poderá chamar ZeroMemory
. Um objeto de memória nativa, como:
- um BSTR
- um HGLOBAL
- Memória não gerenciada CoTaskMem
SecureString devolve a capacidade perdida
No .NET, Strings não podem ser apagadas quando você terminar com elas:
- eles são imutáveis; você não pode substituir o conteúdo deles
- você não pode
Dispose
deles
- a limpeza deles está à mercê do coletor de lixo
O SecureString existe como uma maneira de contornar a segurança das strings e garantir sua limpeza quando necessário.
Você fez a pergunta:
por que não posso apenas dizer:
SecureString password = new SecureString("password");
Porque agora você tem password
na memória; sem nenhuma maneira de limpá-lo. Ele fica preso até que o CLR decida reutilizar essa memória. Você nos colocou de volta onde começamos; um aplicativo em execução com uma senha da qual não podemos nos livrar e onde um despejo de memória (ou Process Monitor) pode ver a senha.
O SecureString usa a API de proteção de dados para armazenar a string criptografada na memória; dessa forma, a string não existirá em arquivos de troca, despejos de memória ou mesmo na janela de variáveis locais com um colega olhando por cima do seu dever.
Como leio a senha?
Então está a pergunta: como interajo com a string? Você absolutamente não quer um método como:
String connectionString = secureConnectionString.ToString()
porque agora você está de volta onde começou - uma senha da qual não pode se livrar. Você deseja forçar os desenvolvedores a manipular a string sensível corretamente - para que ela possa ser apagada da memória.
É por isso que o .NET fornece três funções auxiliares úteis para organizar um SecureString em uma memória não gerenciada:
Você converte a seqüência de caracteres em um blob de memória não gerenciada, manipula-a e limpe-a novamente.
Algumas APIs aceitam SecureStrings . Por exemplo, no ADO.net 4.5, o SqlConnection.Credential usa um conjunto SqlCredential :
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
Você também pode alterar a senha em uma String de conexão:
SqlConnection.ChangePassword(connectionString, cred, newPassword);
E há muitos lugares dentro do .NET em que eles continuam aceitando uma String simples para fins de compatibilidade e, em seguida, mudam rapidamente para um SecureString.
Como colocar texto no SecureString?
Isso ainda deixa o problema:
Como obtenho uma senha no SecureString em primeiro lugar?
Esse é o desafio, mas o objetivo é fazer você pensar em segurança.
Às vezes, a funcionalidade já é fornecida para você. Por exemplo, o controle WPF PasswordBox pode retornar a senha inserida como um SecureString diretamente:
Obtém a senha atualmente mantida pelo PasswordBox como um SecureString .
Isso é útil porque em todos os lugares que você costumava passar uma string não processada, agora você tem o sistema de tipos queixando-se de que o SecureString é incompatível com a String. Você deseja ir o maior tempo possível antes de ter que converter seu SecureString novamente em uma sequência regular.
Converter um SecureString é fácil:
- SecureStringToBSTR
- PtrToStringBSTR
como em:
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;
}
Eles realmente não querem que você faça isso.
Mas como faço para obter uma string em um SecureString? Bem, o que você precisa fazer é parar de ter uma senha em uma String em primeiro lugar. Você precisava tê-lo em outra coisa . Mesmo uma Char[]
matriz seria útil.
É quando você pode anexar cada caractere e limpar o texto simples quando terminar:
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
Você precisa da sua senha armazenada em alguma memória que possa limpar. Carregue-o no SecureString a partir daí.
tl; dr: SecureString existe para fornecer o equivalente a ZeroMemory .
Algumas pessoas não vêem o sentido de limpar a senha do usuário da memória quando um dispositivo está bloqueado ou de pressionar as teclas pressionadas na memória depois de autenticadas . Essas pessoas não usam o SecureString.
SecureString
para um novo desenvolvimento: github.com/dotnet/platform-compat/blob/master/docs/DE0001.md