Segurança em aplicações Web: Injeção de novos parâmetros
Postado em 07. abr, 2009 por Sérgio Lopes em Arquitetura
Seguindo na série sobre Segurança em aplicações Web, vamos falar agora de Injeção de Parâmetros. O outro artigo da série é:
Todo mundo sabe que um dos maiores problemas de segurança é não validar os inputs do usuário. O próprio XSS de certa forma, está ligado a isso, como também o famoso SQL Injection e muitos outros ataques.
Mas sempre fica a dúvida de saber como tratar esses inputs. É um problema realmente complicado determinar que tipos de entradas são válidas em cada request então as pessoas acabam não fazendo nada e aí temos as falhas de segurança. E não adianta deixar tudo inseguro e depois acionar um advogado quando as coisas derem errado, temos que programar direito nossos sites!
Nesse artigo, vou mostrar um exemplo de injeção de parâmetros perigosos e que é muito comum de acontecer por causa da Web e dos frameworks modernos.
Injeção de atributos
Se você usa qualquer framework Java para Web (VRaptor, Struts, Mentawai, Waffle, …) deve estar acostumado com a facilidade de não se preocupar com request.getParameter(). Escrevemos um JavaBean e o framework popula automaticamente os dados pra gente seguindo os nomes do parâmetro.
Imagine um sistema onde as pessoas se cadastram em algum serviço online. Escrevemos uma classe Usuario:
public class Usuario {
private String email;
private String senha;
}
E, no formulário de cadastro, basta enviar os parâmetros usuario.email e usuario.senha.
/usuario/cadastra?usuario.email=example@example.com&usuario.senha=1234
Facilidade! Mas imagine que queremos ter também uma área administrativa e certos usuários com permissão para acessá-la:
public class Usuario {
private String email;
private String senha;
private boolean admin;
}
No formulário de cadastro geral, a pessoa só cadastra email e senha, e no cadastro dentro da área de admin temos um checkbox a mais.
/admin/usuario/cadastra?usuario.email=example@example.com&usuario.senha=1234&usuario.admin=true
Fácil, certo? E extremamente inseguro. E se no cadastro dos usuários normais um usuário mal intencionado passa &usuario.admin=true? Bam! [espero que nenhum leitor desse blog ainda ache que só porque o form do html não tem o campo, estamos seguros]
O problema não existiria se ainda programássemos com request.getParameter(), já que na lógica dos usuários normais obviamente só pegaríamos os parâmetros usuario e email. A questão toda aparece quando usamos as facilidades dos frameworks que saem pegando qualquer parâmetro e jogando nos beans.
Resolvendo
Mas o que fazer? Não usar os frameworks e voltar para as Servlets? Óbvio que não. O primeiro passo é você rever todos os seus códigos atrás desse tipo de falha e perceber o quão grave ele é. Depois partimos para algumas medidas.
A solução mais elgante seria não ter nenhum atributo no seu bean que não pode ser populado pelo usuário. Crie várias classes, se são coisas realmente diferentes (UsuarioNormal e UsuarioAdmin). É a abordagem “white-list“, onde dizemos explicitamente quais são os campos aceitos e qualquer coisa fora disso é ignorada.
Às vezes, não é possível usar o mesmo bean para a pegar os parâmetros e para o Hibernate, por exemplo. Não tente forçar usar o mesmo bean sempre ou você pode cair em casos inseguros que custarão mais dinheiro que as duas classes que você escreveu a mais.
Uma outra solução, se você não pode criar várias classes, é resetar os campos sabidamente exploráveis antes de usá-la:
class UsuarioLogic {
// framework popula o parâmetro
public void cadastra (Usuario u) {
// reseto campos sensíveis
u.setAdmin(false);
// ... uso o objeto
}
}
O problema sobre essa última abordagem é que você está trabalhando no esquema de “black-list“, ou seja, você coloca os atributos problemáticos na lista negra e reseta-os um a um. A dificuldade com isso é saber se, no dia que aparecer um novo atributo problemático, você vai lembrar de resetar seu valor.
Em geral, quando se fala de segurança, soluções white-list são consideradas mais seguras e future-proof que soluções black-list.
Conclusão
Que devemos tratar inputs do usuário, todos sabemos. Mas devemos estar atentos a muitas possibilidades diferentes de injeções maliciosas. As injeções de novos parâmetros são um problema muito comum em especial nos frameworks web que usamos hoje em dia.
Vimos aqui a injeção por meio de beans em frameworks Web Java. Mas esteja certo de não ser vulnerável a injeção de parâmetros em outras frentes, mesmo usando getParameter explicitamente ou usando outras plataformas que não Java.
ASSINE NOSSO RSS




Otávio
12. abr, 2009
Mas essa idéia de usar o pojo do hibernate para popular os dados na web e vice-versa não é uma boa prática segundo os blueprints. O ideal é ter um bean na web (assim como o form no struts) para cada ação do sistema, e depois popular nos pojos persistentes.
E complementando o assunto, vejo vários sites e sistemas web-based que usam campos ocultos, as vezes até mesmo com senhas e valores monetários.
Um exemplo é no site bem famoso de compras, onde você pode fazer a compra normalmente, e quando for fazer o submit dos dados do cartão pode-se alterar o valor a pagar.
Sérgio Lopes
12. abr, 2009
Oi Otávio! O problema de ter essa segunda classe sempre é a repetição de código, de cair nos famosos VOs, tão sabidamente nocivos. O ideal na maioria dos casos seria ter um objeto apenas no seu sistema representando aquele conceito.
Acho que há sim situações onde criar um novo objeto para o form separado do hibernate é interessante, mas só quando realmente envolvem coisas bem diferentes. Se for para copiar e colar código, o ideal é ter um só (com os devidos cuidados, claro).
Paulo Silveira
20. jun, 2010
O Sergio lembrou bem:
http://www.springsource.com/security/cve-2010-1622
Esse grave bug do Spring esta relacionado a esses problemas.