Use a matriz char [] sobre uma seqüência de caracteres para manipular senhas em Java?
1. Visão geral
Neste artigo, explicaremos por que devemos usar a matrizchar[] para representar senhas em vez deString em Java.
Observe que este tutorial foca nas formas de manipulação de senhas na memória, não nas formas reais de armazená-las, o que geralmente é feito na camada de persistência.
Também presumimos que não podemos controlar o formato da senha (por exemplo a senha vem da API de terceiros na forma deString). Embora pareça óbvio usar o objeto do tipojava.lang.String para manipular senhas, é recomendado pela própria equipe Java usarchar[].
Por exemplo, se dermos uma olhada emJPasswordField dejavax.swing, podemos ver que o métodogetText() que retornaString está obsoleto desde Java 2 e foi substituído porgetPassword() método que retornachar[].
Então, vamos explorar algumas razões fortes por que esse é o caso.
2. Strings são imutáveis
Strings em Java são imutáveis, o que significa que não podemos alterá-los usando APIs de alto nível. Qualquer alteração em um objetoString produzirá um novoString, mantendo o antigo na memória.
Portanto, a senha armazenada emString ficará disponível na memória até que o Coletor de Lixo a apague. Não podemos controlar quando isso acontece, mas este período pode ser significativamente mais longo do que para objetos regulares, uma vez queStrings são mantidos em um String Pool para fins de reutilização.
Conseqüentemente, qualquer pessoa com acesso ao despejo de memória pode recuperar a senha da memória.
Com um arraychar[] em vez deString, podemos limpar os dados explicitamente após terminarmos o trabalho pretendido. Dessa forma, garantiremos que a senha seja removida da memória antes mesmo de ocorrer a coleta de lixo.
Vamos agora dar uma olhada nos snippets de código, que demonstram o que acabamos de discutir.
Primeiro paraString:
System.out.print("Original String password value: ");
System.out.println(stringPassword);
System.out.println("Original String password hashCode: "
+ Integer.toHexString(stringPassword.hashCode()));
String newString = "********";
stringPassword.replace(stringPassword, newString);
System.out.print("String password value after trying to replace it: ");
System.out.println(stringPassword);
System.out.println(
"hashCode after trying to replace the original String: "
+ Integer.toHexString(stringPassword.hashCode()));
A saída será:
Original String password value: password
Original String password hashCode: 4889ba9b
String value after trying to replace it: password
hashCode after trying to replace the original String: 4889ba9b
Agora, parachar[]:
char[] charPassword = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
System.out.print("Original char password value: ");
System.out.println(charPassword);
System.out.println(
"Original char password hashCode: "
+ Integer.toHexString(charPassword.hashCode()));
Arrays.fill(charPassword, '*');
System.out.print("Changed char password value: ");
System.out.println(charPassword);
System.out.println(
"Changed char password hashCode: "
+ Integer.toHexString(charPassword.hashCode()));
A saída é:
Original char password value: password
Original char password hashCode: 7cc355be
Changed char password value: ********
Changed char password hashCode: 7cc355be
Como podemos ver, depois de tentarmos substituir o conteúdo doString original, o valor permanece o mesmo e o métodohashCode() não retornou um valor diferente na mesma execução do aplicativo, o que significa que o String original permaneceu intacto.
E para o arraychar[], fomos capazes de alterar os dados no mesmo objeto.
3. Podemos imprimir senhas acidentalmente
Outro benefício de trabalhar com senhas no arraychar[] é a prevenção do log acidental da senha em consoles, monitores ou outros locais mais ou menos inseguros.
Vamos verificar o próximo código:
String passwordString = "password";
char[] passwordArray = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
System.out.println("Printing String password -> " + passwordString);
System.out.println("Printing char[] password -> " + passwordArray);
Com a saída:
Printing String password -> password
Printing char[] password -> [[email protected]
Vemos que o próprio conteúdo é impresso no primeiro caso, enquanto no segundo caso, os dados não são tão úteis, o que tornachar[] menos vulnerável.
4. Conclusão
Neste artigo rápido, enfatizamos vários motivos pelos quais não devemos usarStrings para coletar senhas e por que devemos usar arrayschar[].
Como sempre, trechos de código podem ser encontradosover on GitHub.