Segurança em aplicações Web: Injeção de novos parâmetros

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 é:


SegurançaTodo 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.

6 Comentários

  1. Otávio 12/04/2009 at 03:51 #

    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.

  2. Sérgio Lopes 12/04/2009 at 04:33 #

    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).

  3. Paulo Silveira 20/06/2010 at 01:49 #

    O Sergio lembrou bem:
    http://www.springsource.com/security/cve-2010-1622
    Esse grave bug do Spring esta relacionado a esses problemas.

  4. Sérgio Lopes 04/03/2012 at 22:11 #

    E aconteceu de novo com mais um grande… Github dessa vez:

    https://github.com/blog/1068-public-key-security-vulnerability-and-mitigation

  5. Ricardo 26/11/2013 at 14:25 #

    No Spring eles recomendam criar um array com apenas os campos que possam ser manipulados e na inicialização do controller indicar esses campos através do método setAllowedFields. No Vraptor tem algum mecanismo semelhante?

Deixe uma resposta