24 de JULHO de 2023
Não é incomum nos depararmos com notícias sobre incidentes de Segurança da Informação que resultaram em vazamento de dados, ou até mesmo de senhas. Dados provenientes destes incidentes são vendidos à altos preços em mercados clandestinos, e seu valor e procura aumentam quando a base de dados inclui a senha dos usuários.
Por mais renomada que seja a plataforma que estamos utilizando, ou até mesmo, por maiores que sejam as auditorias e avaliações de segurança, não devemos ser negligentes quando falamos de senhas. Senhas ainda são o principal mecanismo de autenticação, que provam que um usuário é quem ele diz ser. Muito embora hoje existem mecanismos para proteger ainda mais o usuário, como autenticação multifator, as senhas ainda são de interesse dos atacantes pois a esmagadora maioria dos usuários utiliza a mesma senha para mais de uma autenticação, e mais ainda: utiliza sua senha para fins pessoais e profissionais, fazendo com que exista uma porta de entrada para ataques em ambientes corporativos.
Para entender como funciona um ataque às senhas, primeiro precisamos entender o que acontece (ou deveria acontecer) em uma aplicação que armazena senhas de seus usuários.
Em primeiro lugar, não é uma boa prática guardar uma senha (nem mesmo utilizando criptografia) diretamente em um banco de dados. Para isso, é armazenada a soma hash da senha. Para fins didáticos, é interessante pensar em uma hash como uma via de mão única, em que após calculada a hash de um determinado elemento, este não pode ser obtido a partir desta hash. Um algoritmo simples, porém, bastante comum para cálculo de hashes é o MD5. Para exemplo, observe a tabela abaixo:
Palavra | Hash MD5 |
integrasul | 9029bc9dc3f01c72288055bb4d0a89ee |
segurança | 7ab0a090390cffb689ea1c5a56020f68 |
Integrasul | 72f77fe73a73443aebaa526fc8cfae48 |
Observe, por exemplo, a primeira e a terceira linha. Só existe uma letra maiúscula como diferença entre as duas, e mesmo assim, a hash é completamente diferente. Esta propriedade das hashes permite com que não seja possível inferir a entrada tendo como base somente a hash.
Para o armazenamento de senhas, a ideia de hash é muito boa, já que não é possível reverter a hash para descobrir a senha que o usuário salvou na aplicação, e sempre que o usuário tentar se autenticar, bastaria calcular a hash da senha informada e comparar com a hash salva no banco de dados. Como foi visto, qualquer letra diferente gera uma hash totalmente diferente, fazendo com que uma senha semelhante não autentique o usuário.
Bem, na teoria, tudo parece perfeito, porém, na prática, existem outros riscos a serem avaliados.
Vamos tomar como exemplo uma aplicação hipotética que sofreu um vazamento de dados, e dentre os dados vazados, está o hash das senhas. Mesmo que não seja possível obter as senhas através dos dados vazados, ainda é possível lançar um ataque para descobrir as senhas que geraram tais hashes.
E este ataque é mais simples do que parece. Pense: se uma senha (que não conheço ainda) gerou uma hash utilizando o algoritmo MD5, é possível facilmente criar uma lista de possíveis senhas, calcular a hash de todas e fazer uma comparação. Se o resultado encontrado for semelhante à hash contida no banco de dados, eu encontrei a senha do usuário.
Nos dias atuais, com o avanço da capacidade de processamento computacional, as boas práticas para o desenvolvimento de aplicações sugerem que a sejam utilizados algoritmos mais robustos para cálculo da hash, e que a hash armazenada no banco de dados não seja somente uma hash da senha do usuário, mas sim uma hash da senha concatenada com alguma aleatoriedade. Esta aleatoriedade é chamada de salt. Veja como a adição de um salt é feita na prática, utilizando o mesmo algoritmo MD5 já mencionado anteriormente:
Palavra | salt | Palavra + salt | Hash MD5 |
integrasul | EY4ekUsSLs4vu3CJ | integrasulEY4ekUsSLs4vu3CJ | c26fb42433dff75827c4a6ae0da35c1c |
segurança | EY4ekUsSLs4vu3CJ | segurançaEY4ekUsSLs4vu3CJ | e8689c7b29501c873d01759dc97ae87d |
Integrasul | EY4ekUsSLs4vu3CJ | IntegrasulEY4ekUsSLs4vu3CJ | d41d8cd98f00b204e9800998ecf8427e |
Da perspectiva de um atacante que está em posse destes dados, obter as hashes não necessariamente implica em obter as senhas dos usuários. Entretanto, é bastante comum utilizar algumas técnicas (que nada têm de muito misterioso) para conseguir ao menos uma senha válida, e a partir desta, obter outras.
Um dos primeiros pontos a ser observado é o simples fato de existirem hashes iguais dentro do banco de dados. Ora, se as hashes são idênticas, por mais que o algoritmo seja robusto o suficiente e ainda que seja feita a utilização de salt para o armazenamento da hash, é notável que a senha cadastrada pelos usuários é uma senha comum e fraca. Por maiores que sejam os mecanismos de segurança implementados pela aplicação, a senha informada pelo usuário ainda compõe a cadeia de segurança, se tornando assim o elo mais fraco da corrente.
É comum as aplicações solicitarem requisitos de complexidade no cadastro de senhas. Comumente, estes requisitos envolvem comprimento mínimo de 8 caracteres e o uso de letras maiúsculas, minúsculas, números e caracteres especiais. Entretanto, uma senha fraca como Asdf@123 ou até mesmo Empresa@2023 já satisfazem estes requisitos. Com o emprego de certo esforço - e tempo - é possível descobrir não só a senha do usuário, mas também o salt utilizado para a geração das hashes. E, com o salt comprometido, todas as hashes ficam vulneráveis à quebra de senha por tentativa e erro.
De posse da lista de hashes, um atacante consegue apenas saber que o algoritmo que gerou a hash é o MD5, porém não consegue estimar o tempo necessário para que a senha por trás da hash seja descoberta, e obviamente, o tempo necessário para descoberta das senhas da Tabela 2 é muito maior que o tempo necessário para a Tabela 1.
Ok, e o que eu como usuário posso fazer para garantir minha segurança?
Mesmo que já existam mecanismos para burlar, é importante que, sempre que possível, a autenticação multifator esteja habilitada e funcional. Em resumo, um fator de autenticação é uma "etapa" relacionada ao usuário. Isso é: uma senha é algo que o usuário sabe. Adicionando uma notificação push no smartphone, é adicionado algo que o usuário possui; adicionando a confirmação por impressão digital, é algo que o usuário é. E com isso, são adicionadas mais camadas de segurança que fazem com que seja cada vez mais difícil um atacante se autenticar com sua conta.
Não só a autenticação multifator, mas também é de extrema importância uma senha forte, de preferência gerada aleatoriamente e que não seja utilizada em nenhum outro local.
Quando estas duas premissas para o uso de senhas são colocadas lado a lado, o usuário sempre se pergunta: "Como eu vou lembrar de todas as senhas, se elas devem ser aleatórias e não devo reutilizá-las?". Hoje existem alternativas como cofres de senhas, que além de gerar uma senha suficientemente segura, ainda armazenam esta senha e disponibilizam ela durante o processo de login na aplicação. Cofres de senhas hoje já contam com mecanismos suficientemente fortes para garantir a segurança das senhas, incluindo criptografia de última geração e autenticação multifator para ter acesso às senhas. Mesmo assim, é importante que a segurança da "senha mestra" cadastrada no cofre não seja negligenciada, para não se tornar o elo mais fraco da corrente (afinal, é muito mais fácil lembrar de apenas uma senha forte).