texto - validar char java




Por que o char[] é preferido em relação ao String para senhas? (12)

No Swing, o campo de senha tem um getPassword() (retorna char[] ) em vez do método usual getText() (retorna String ). Da mesma forma, me deparei com uma sugestão para não usar o String para manipular senhas.

Por que a String representa uma ameaça à segurança quando se trata de senhas? Parece inconveniente usar char[] .


  1. As strings são imutáveis em Java se você armazenar a senha como texto simples, ela ficará disponível na memória até que Garbage collector a apague e, como Strings são usados ​​no pool de String para reutilização, há uma grande chance de permanecer na memória por um longo tempo. duração, o que representa uma ameaça à segurança. Desde que qualquer pessoa que tenha acesso ao despejo de memória pode encontrar a senha em texto não criptografado
  2. Recomendação Java usando o método getPassword() do JPasswordField que retorna um método char [] e obsoleto getText() que retorna a senha em texto claro indicando o motivo da segurança.
  3. toString () sempre existe o risco de imprimir texto simples no arquivo de log ou no console, mas se usar o Array, você não imprimirá o conteúdo do array, em vez disso, o local da memória será impresso.

    String strPwd = "passwd";
    char[] charPwd = new char[]{'p','a','s','s','w','d'};
    System.out.println("String password: " + strPwd );
    System.out.println("Character password: " + charPwd );
    

    Senha da string: passwd

    Senha do personagem: [C @ 110b2345

Considerações finais: Embora usar char [] não seja suficiente, você precisa apagar o conteúdo para ser mais seguro. Eu também sugiro trabalhar com senha criptografada ou hash em vez de texto sem formatação e limpá-lo da memória assim que a autenticação for concluída.


A resposta já foi dada, mas gostaria de compartilhar um problema que descobri recentemente com bibliotecas padrão Java. Enquanto eles tomam muito cuidado agora de substituir strings de senha por char[] todos os lugares (o que obviamente é uma coisa boa), outros dados críticos de segurança parecem ser ignorados quando se trata de limpá-lo da memória.

Estou pensando, por exemplo, na classe PrivateKey . Considere um cenário em que você carregaria uma chave RSA privada de um arquivo PKCS # 12, usando-o para executar alguma operação. Agora, neste caso, farejar a senha por si só não ajudaria muito, desde que o acesso físico ao arquivo de chave seja adequadamente restrito. Como um invasor, você ficaria muito melhor se obtivesse a chave diretamente em vez da senha. A informação desejada pode ser vazada múltiplas, core dumps, uma sessão de depurador ou arquivos de swap são apenas alguns exemplos.

E, como se constata, não há nada que permita limpar as informações particulares de um PrivateKey da memória, porque não há API que permita limpar os bytes que formam as informações correspondentes.

Esta é uma situação ruim, já que este paper descreve como esta circunstância poderia ser potencialmente explorada.

A biblioteca OpenSSL, por exemplo, sobrescreve seções críticas de memória antes que chaves privadas sejam liberadas. Como o Java é coletor de lixo, precisaríamos de métodos explícitos para limpar e invalidar informações particulares de chaves Java, que devem ser aplicadas imediatamente após o uso da chave.


Como Jon Skeet afirma, não há como usar a reflexão.

No entanto, se a reflexão é uma opção para você, você pode fazer isso.

public static void main(String[] args) {
    System.out.println("please enter a password");
    // don't actually do this, this is an example only.
    Scanner in = new Scanner(System.in);
    String password = in.nextLine();
    usePassword(password);

    clearString(password);

    System.out.println("password: '" + password + "'");
}

private static void usePassword(String password) {

}

private static void clearString(String password) {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        char[] chars = (char[]) value.get(password);
        Arrays.fill(chars, '*');
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

quando correr

please enter a password
hello world
password: '***********'

Nota: se o caractere String [] foi copiado como parte de um ciclo de GC, existe uma chance de a cópia anterior estar em algum lugar na memória.

Essa cópia antiga não apareceria em um dump de heap, mas se você tiver acesso direto à memória bruta do processo, poderá vê-la. Em geral, você deve evitar que alguém tenha esse acesso.


Embora outras sugestões aqui pareçam válidas, existe outro bom motivo. Com o Simple String você tem chances muito maiores de imprimir acidentalmente a senha em logs , monitores ou algum outro local inseguro. char[] é menos vulnerável.

Considere isto:

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

Impressões:

String: Password
Array: [[email protected]

Matrizes de char[] ( char[] ) podem ser apagadas após o uso, definindo cada caractere como zero e não como Strings. Se alguém puder ver a imagem da memória de alguma forma, ela poderá ver uma senha em texto sem formatação se as Strings forem usadas, mas se char[] for usado, depois de limpar os dados com 0, a senha será segura.


Não acho que seja uma sugestão válida, mas posso pelo menos adivinhar o motivo.

Eu acho que a motivação é querer ter certeza de que você pode apagar todos os vestígios da senha na memória imediatamente e com certeza depois de ser usada. Com um char[] você poderia sobrescrever cada elemento da matriz com um espaço em branco ou algo com certeza. Você não pode editar o valor interno de uma String dessa maneira.

Mas isso sozinho não é uma boa resposta; por que não apenas garantir que uma referência ao char[] ou String não escape? Então não há problema de segurança. Mas a coisa é que os objetos String podem ser intern() em teoria) e mantidos vivos dentro do pool constante. Eu suponho que usar char[] proíba essa possibilidade.


Para citar um documento oficial, o guia Java Cryptography Architecture diz isso sobre as senhas char[] vs. String (sobre criptografia baseada em senha, mas isso é mais geralmente sobre senhas, é claro):

Parece lógico coletar e armazenar a senha em um objeto do tipo java.lang.String . No entanto, aqui está a ressalva: Os Object do tipo String são imutáveis, ou seja, não há métodos definidos que permitam alterar (sobrescrever) ou zerar o conteúdo de uma String após o uso. Esse recurso torna os objetos String impróprios para armazenar informações confidenciais de segurança, como senhas de usuários. Você deve sempre coletar e armazenar informações confidenciais de segurança em uma matriz de char .

A Diretriz 2-2 das Diretrizes de Codificação Segura para a Linguagem de Programação Java, Versão 4.0, também diz algo semelhante (embora seja originalmente no contexto do logging):

Diretriz 2-2: Não registre informações altamente confidenciais

Algumas informações, como números de segurança social (SSNs) e senhas, são altamente confidenciais. Esta informação não deve ser mantida por mais tempo do que o necessário nem onde possa ser vista, mesmo pelos administradores. Por exemplo, ele não deve ser enviado para arquivos de log e sua presença não deve ser detectada por meio de pesquisas. Alguns dados transitórios podem ser mantidos em estruturas de dados mutáveis, como matrizes de caracteres, e limpos imediatamente após o uso. A limpeza de estruturas de dados reduziu a eficácia em sistemas de tempo de execução Java típicos à medida que os objetos são movidos na memória de forma transparente para o programador.

Essa diretriz também tem implicações para a implementação e uso de bibliotecas de nível inferior que não possuem conhecimento semântico dos dados com os quais estão lidando. Por exemplo, uma biblioteca de análise de cadeia de caracteres de baixo nível pode registrar o texto em que está trabalhando. Um aplicativo pode analisar um SSN com a biblioteca. Isso cria uma situação em que os SSNs estão disponíveis para administradores com acesso aos arquivos de log.


Cordas são imutáveis . Isso significa que, uma vez que você tenha criado a String , se outro processo puder despejar memória, não há como (além de reflection ) você pode se livrar dos dados antes que a coleta de lixo seja iniciada.

Com um array, você pode apagar explicitamente os dados depois de terminar. Você pode sobrescrever a matriz com qualquer coisa que desejar e a senha não estará presente em nenhum lugar do sistema, mesmo antes da coleta de lixo.

Então, sim, isso é uma preocupação de segurança - mas até mesmo usar o char[] reduz apenas a janela de oportunidade para um invasor, e é somente para esse tipo específico de ataque.

Conforme observado nos comentários, é possível que matrizes sendo movidas pelo coletor de lixo deixem cópias dispersas dos dados na memória. Eu acredito que isso é específico da implementação - o coletor de lixo pode limpar toda a memória, evitando esse tipo de coisa. Mesmo que isso aconteça, ainda há o tempo durante o qual o char[] contém os caracteres reais como uma janela de ataque.


1) Como Strings são imutáveis ​​em Java se você armazenar a senha como texto simples, ela estará disponível na memória até que Garbage collector a limpe e como String é usada no pool de String para reutilização, há uma grande chance de permanecer na memória para a longa duração, o que representa uma ameaça à segurança. Como qualquer pessoa que tenha acesso ao despejo de memória pode encontrar a senha em texto não criptografado e essa é outra razão pela qual você deve sempre usar uma senha criptografada em vez de texto sem formatação. Como as Strings são imutáveis, não há como o conteúdo de Strings ser alterado porque qualquer alteração produzirá uma nova String, enquanto se você char [] você ainda pode definir todos os seus elementos como em branco ou zero. Portanto, armazenar a senha na matriz de caracteres reduz o risco de roubar a senha.

2) O próprio Java recomenda o uso do método getPassword () do JPasswordField, que retorna um método char [] e obsoleto getText (), que retorna a senha em texto claro indicando o motivo de segurança. É bom seguir o conselho da equipe de Java e aderir ao padrão, em vez de ir contra.


A resposta curta e direta seria porque char[]é mutável enquanto os Stringobjetos não são.

Stringsem Java são objetos imutáveis. É por isso que eles não podem ser modificados depois de criados e, portanto, a única maneira de o conteúdo deles ser removido da memória é coletar lixo. Será somente quando a memória liberada pelo objeto puder ser sobrescrita e os dados desaparecerem.

Agora, a coleta de lixo em Java não acontece em nenhum intervalo garantido. O Stringpode, portanto, persistir na memória por um longo tempo, e se um processo falhar durante esse tempo, o conteúdo da seqüência de caracteres pode acabar em um despejo de memória ou algum log.

Com uma matriz de caracteres , você pode ler a senha, terminar de trabalhar com ela o mais rápido possível e, em seguida, alterar imediatamente o conteúdo.


String é imutável e vai para o pool de strings. Uma vez escrita, não pode ser sobrescrita.

char[] é uma matriz que você deve sobrescrever uma vez que você usou a senha e é assim que deve ser feito:

char[] passw = request.getPassword().toCharArray()
if (comparePasswords(dbPassword, passw) {
 allowUser = true;
 cleanPassword(passw);
 cleanPassword(dbPassword);
 passw=null;
}

private static void cleanPassword (char[] pass) {
 for (char ch: pass) {
  ch = null;
 }
}

Um cenário em que o invasor poderia usá-lo é um crashdump - quando a JVM falha e gera um despejo de memória - você poderá ver a senha.

Isso não é necessariamente um invasor externo mal-intencionado. Pode ser um usuário de suporte que tenha acesso ao servidor para fins de monitoramento. Ele poderia espreitar um crashdump e encontrar as senhas.


String em java é imutável. Então, sempre que uma string é criada, ela permanecerá na memória até ser coletada como lixo. Então, qualquer pessoa que tenha acesso à memória pode ler o valor da string.
Se o valor da string for modificado, ele acabará criando uma nova string. Portanto, tanto o valor original quanto o valor modificado permanecem na memória até serem coletados como lixo.

Com a matriz de caracteres, o conteúdo da matriz pode ser modificado ou apagado depois que o objetivo da senha é exibido. O conteúdo original da matriz não será encontrado na memória depois que ele for modificado e até mesmo antes da coleta de lixo entrar em ação.

Devido à preocupação de segurança, é melhor armazenar a senha como uma matriz de caracteres.





char