Estou tentando entender o objetivo do SecureString do .NET. Do MSDN:
Uma instância da classe System.String é imutável e, quando não é mais necessária, não pode ser agendada programaticamente para coleta de lixo; isto é, a instância é somente leitura depois de criada e não é possível prever quando a instância será excluída da memória do computador. Conseqüentemente, se um objeto String contiver informações confidenciais, como senha, número do cartão de crédito ou dados pessoais, existe o risco de as informações serem reveladas depois de usadas, porque o aplicativo não pode excluir os dados da memória do computador.
Um objeto SecureString é semelhante a um objeto String, pois possui um valor de texto. No entanto, o valor de um objeto SecureString é criptografado automaticamente, pode ser modificado até que o aplicativo o marque como somente leitura e pode ser excluído da memória do computador pelo aplicativo ou pelo coletor de lixo do .NET Framework.
O valor de uma instância do SecureString é criptografado automaticamente quando a instância é inicializada ou quando o valor é modificado. Seu aplicativo pode tornar a instância imutável e impedir modificações adicionais, invocando o método MakeReadOnly.
A criptografia automática é o grande retorno?
E por que não posso apenas dizer:
SecureString password = new SecureString("password");
ao invés de
SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
pass.AppendChar(c);
Que aspecto do SecureString estou ausente?
fonte
SecureString
para um novo desenvolvimento: github.com/dotnet/platform-compat/blob/master/docs/DE0001.mdRespostas:
Eu pararia de usar o SecureString. Parece que os caras do PG estão deixando de lado o suporte. Possivelmente até faça isso no futuro - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .
fonte
Algumas partes da estrutura que atualmente usam
SecureString
:System.Windows.Controls.PasswordBox
controle do WPF mantém a senha como SecureString internamente (exposta como uma cópiaPasswordBox::SecurePassword
)System.Diagnostics.ProcessStartInfo::Password
propriedade é umaSecureString
X509Certificate2
leva umSecureString
para a senhaO principal objetivo é reduzir a superfície de ataque, em vez de eliminá-la.
SecureStrings
são "fixados" na RAM para que o Garbage Collector não o mova ou faça cópias dele. Também garante que o texto simples não seja gravado no arquivo Swap ou nos dumps principais. A criptografia é mais como ofuscação e, no entanto, não impede um determinado hacker, que seria capaz de encontrar a chave simétrica usada para criptografar e descriptografar.Como outros já disseram, a razão pela qual você deve criar um
SecureString
caractere por caractere é a primeira falha óbvia de agir de outra maneira: você provavelmente já tem o valor secreto como uma string simples, então qual é o sentido?SecureString
s são o primeiro passo para resolver um problema de ovos e galinhas, portanto, embora a maioria dos cenários atuais exija convertê-los novamente em seqüências regulares para fazer qualquer uso deles, sua existência na estrutura agora significa um melhor suporte para eles. futuro - pelo menos até um ponto em que seu programa não precise ser o elo mais fraco.fonte
Editar : Não use SecureString
A orientação atual agora diz que a classe não deve ser usada. Os detalhes podem ser encontrados neste link: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Do artigo:
DE0001: SecureString não deve ser usado
Motivação
SecureString
é evitar ter segredos armazenados na memória do processo como texto sem formatação.SecureString
não existe como um conceito de sistema operacional.System.String
- a vida útil do buffer nativo é mais curta.Recomendação
Não use
SecureString
para novo código. Ao portar código para o .NET Core, considere que o conteúdo da matriz não está criptografado na memória.A abordagem geral de lidar com credenciais é evitá-las e confiar em outros meios de autenticação, como certificados ou autenticação do Windows.
Fim da edição: resumo original abaixo
Muitas ótimas respostas; Aqui está uma rápida sinopse do que foi discutido.
A Microsoft implementou a classe SecureString em um esforço para fornecer melhor segurança com informações confidenciais (como cartões de crédito, senhas etc.). Ele fornece automaticamente:
Atualmente, o SecureString é limitado em uso, mas espera uma melhor adoção no futuro.
Com base nessas informações, o construtor do SecureString não deve apenas pegar uma string e dividi-la na matriz char, pois a string soletrada derrota o objetivo do SecureString.
Informação adicional:
Editar: achei difícil escolher a melhor resposta, pois há muitas informações em muitas; Pena que não há opções de resposta assistida.
fonte
Resposta curta
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
:Nota : SecureZeroMemory is é idêntico a
ZeroMemory
, exceto pelo compilador que não será otimizado.O problema é que você não pode ligar
ZeroMemory
ouSecureZeroMemory
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: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:SecureString devolve a capacidade perdida
No .NET, Strings não podem ser apagadas quando você terminar com elas:
Dispose
delesO SecureString existe como uma maneira de contornar a segurança das strings e garantir sua limpeza quando necessário.
Você fez a pergunta:
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:
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 :
Você também pode alterar a senha em uma String de conexão:
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:
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:
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:
como em:
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:
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.
fonte
Existem muito poucos cenários em que você pode usar o SecureString de forma sensata na versão atual do Framework. É realmente útil apenas para interagir com APIs não gerenciadas - você pode empacotá-lo usando Marshal.SecureStringToGlobalAllocUnicode.
Assim que você o converte em / para um System.String, você perde o objetivo.
A amostra do MSDN gera o SecureString um caractere por vez da entrada do console e passa a string segura para uma API não gerenciada. É bastante complicado e irreal.
Você pode esperar que versões futuras do .NET tenham mais suporte ao SecureString, o que o tornará mais útil, por exemplo:
SecureString Console.ReadLineSecure () ou similar para ler a entrada do console em um SecureString sem todo o código complicado da amostra.
Substituição WinForms TextBox que armazena sua propriedade TextBox.Text como uma seqüência de caracteres segura para que as senhas possam ser inseridas com segurança.
Extensões para APIs relacionadas à segurança para permitir que senhas sejam passadas como SecureString.
Sem o exposto, o SecureString terá um valor limitado.
fonte
Eu acredito que a razão pela qual você precisa fazer o acréscimo de caracteres em vez de uma instanciação simples é porque, em segundo plano, passar "password" para o construtor do SecureString coloca a string "password" na memória, derrotando o objetivo da string segura.
Ao anexar, você está apenas colocando um personagem de cada vez na memória, o que provavelmente não será adjacente um ao outro, dificultando muito a reconstrução da string original. Eu poderia estar errado aqui, mas foi assim que me foi explicado.
O objetivo da classe é impedir que dados seguros sejam expostos por meio de um despejo de memória ou ferramenta semelhante.
fonte
A Microsoft descobriu que, em certas instâncias em que o servidor (desktop, qualquer que seja) travasse, havia momentos em que o ambiente de tempo de execução realizava um despejo de memória, expondo o conteúdo do conteúdo da memória. O Secure String o criptografa na memória para impedir que o invasor possa recuperar o conteúdo da string.
fonte
Um dos grandes benefícios de um SecureString é que ele evita a possibilidade de seus dados serem armazenados em disco devido ao cache da página. Se você tiver uma senha na memória e, em seguida, carregar um programa ou conjunto de dados grande, sua senha poderá ser gravada no arquivo de troca à medida que o programa for paginado com falta de memória. Com um SecureString, pelo menos os dados não ficarão indefinidamente no disco em texto não criptografado.
fonte
Eu acho que é porque a string é para ser segura, ou seja, um hacker não deve ser capaz de lê-la. Se você inicializá-lo com uma sequência, o hacker poderá ler a sequência original.
fonte
Bem, como a descrição declara, o valor é armazenado criptografado, o que significa que um despejo de memória do processo não revelará o valor da string (sem algum trabalho bastante sério).
O motivo pelo qual você não pode simplesmente construir um SecureString a partir de uma cadeia constante é porque você teria uma versão não criptografada da cadeia na memória. Limitar a criação da cadeia em partes reduz o risco de manter toda a cadeia na memória de uma só vez.
fonte
Outro caso de uso é quando você está trabalhando com aplicativos de pagamento (POS) e simplesmente não pode usar estruturas de dados imutáveis para armazenar dados confidenciais porque é um desenvolvedor cuidadoso. Por exemplo: se eu armazenarei dados confidenciais do cartão ou metadados de autorização em uma sequência imutável, sempre haveria o caso em que esses dados estarão disponíveis na memória por um período significativo de tempo após serem descartados. Não posso simplesmente substituí-lo. Outra grande vantagem é que esses dados confidenciais são mantidos na memória criptografada.
fonte