Segurança em aplicações Web: XSS

Por Sérgio Lopes em 25/11/08

Bons tempos aqueles quando os computadores não eram ligados em rede, não existia Internet e as aplicações eram todas Desktop. Em tempos de Web 2.0, Mashups e Aplicativos Web, as dores de cabeça são absurdamente maiores assim como o número de aplicações expostas a ataques. Seu sistema é seguro?

Ultimamente tenho notado como poucas pessoas se preocupam de verdade com segurança na web, ou pior, como os desenvolvedores desconhecem os problemas envolvidos na programação pra web. É preciso entender como o HTTP funciona, como os browsers funcionam, o que o JavaScript é capaz de fazer e até as implicações de segurança dos ingênuos HTML e CSS.

Pensando nisso, resolvi escrever uma série de artigos sobre segurança em aplicações Web e começo falando do famoso Cross-site Scripting, carinhosamente chamado de XSS.

Samy is my hero

Em 2005, Samy Kankar, insatisfeito com sua pequena quantidade de amigos no MySpace, escreveu um worm (depois batizado de JS.Spacehero) para turbinar sua lista de amigos.

O script rodava quando alguém simplesmente visitava o perfil de Samy, adicionava o visitante à sua lista de amigos e colocava no perfil do infectado a frase “samy is my hero“. Além disso, o script se propagava para o perfil do usuário infectado, possibilitando que esse infectasse mais pessoas.

Em menos de 20h, Samy tinha um milhão de amigos e o MySpace foi tirado do ar. A aventura ingênua de Samy (com a falha que ele descobriu, poderia ter feito algo bem pior) foi narrada de forma muito cômica no site dele. E, em 2007, lhe rendeu uma condenação nos tribunais com direito à multa, serviço comunitário e afastamento de computadores.

Mas o que o bravo Samy descobriu?

Não confie nos inputs de seus usuários

O MySpace é conhecido pela papagaiada permitida nos perfis dos usuários. Diferente do Orkut, por exemplo, o dono do perfil do MySpace pode mudar praticamente todas as características visuais do site (fundo, cores, letras, imagens, vídeos etc). Para isso, o MySpace aceita que o usuário digite HTML e CSS para personalizar sua página, mas com limites para a coisa não virar zona.

O que Samy fez? Descobriu uma falha no filtro do MySpace que limita os inputs e conseguiu colocar em seu perfil um código JavaScript que seria executado por cada visitante do seu perfil. Com técnicas de Ajax e um pouco de tempo livre, Samy fez um JavaScript que executava as ações descritas acima.

XSS - Cross-site scripting

Um ataque XSS é aquele que permite a injeção de scripts no site atacado, em geral por meio de algum campo de input do usuário. Note que um ataque XSS é um ataque ao usuário do site e não ao sistema servidor em si. Isso porque o script injetado nunca será executado no servidor, mas sim nos navegadores dos clientes que visitarem a página infectada.

A regra de ouro de qualquer sistema com input de usuários é que não devemos confiar jamais naquilo que o usuário digitou. Além de XSS, podemos ser alvos de muitos outros ataques, como SQL Injection, injeção de parâmetros e outros (quem sabe abordamos num artigo futuro).

Embora pareça simples, a OWASP (Open Web Application Security Project) diz que nada menos que 9 em cada 10 sites estão vulneráveis a esse tipo de ataque. Anualmente, eles fazem um estudo das 10 falhas mais encontradas na Web, e no ano passado, XSS foi o campeão.

Como se proteger

Todo input do usuário deve ser sanitizado antes de qualquer coisa. Isso significa passar algum tipo de filtro que consiga remover tags potencialmente perigosas.

Se o seu site não deve ser customizado pelo usuário de nenhuma forma e o input dele deveria ser texto puro, basta remover toda e qualquer tag encontrada. Mas o caso mais complicado (aqui entra o MySpace) é quando você deseja permitir certas tags (negrito, por exemplo) e qual abordagem seguir para filtrar as tags não desejadas.

É considerado, hoje, total insanidade mental e causa da maioria das vulnerabilidades de XSS, tentar escrever esse filtro de input sozinho. Ele é extremamente complexo. Pense no caso simples, aquele onde não desejamos aceitar nenhuma tag. 99% das pessoas pensariam que o código abaixo faz um excelente trabalho:
String limpo = input.replaceAll("<", "").replaceAll(">“, “”);

É um código Java que transforma:
<script>alert('XSS');</script>

…nisso (claramente inofensivo):
scriptalert('XSS');/script

E o código abaixo então?
+ADw-script+AD4-alert('XSS')+ADw-/script+AD4-

Esse código é executado por qualquer navegador atual usando codificação UTF-7. E obviamente aqueles nossos “replaceAll” não resolvem o problema. Há centenas de outros exemplos que usam encodings estranhos, html entities, carateres especiais no meio etc.

E isso com o objetivo de tirar todas as tags da frente. E quando queremos que algumas sejam aceitas? Quais tags são seguras? E os atributos nessas tags? Até um <img> com atributo src apenas está vulnerável se não tomarmos cuidado.

Moral da história: fazer os replacezinhos na mão é insano. Não fazer nada a respeito é suicídio.

Arrumando o problema

Precisamos sanitizar o input dos usuários e precisamos de algo pronto que faça isso. Há trocentos projetos por aí que fazem esse tipo de serviço. Em especial, o AntiSamy do pessoal da OWASP que tem versões em Java e .Net. A Microsoft tem uma API anti-XSS para .Net. Há ainda o HtmlPurifier para PHP, o sanitize do Ruby on Rails e muitos outros em outras plataformas.

O AntiSamy é bastante customizável, permitindo que definamos níveis diferentes de purificação através de regras em um XML. Ele ainda é capaz de mostrar mensagens de erros amigáveis para os usuários. Usá-lo é bem simples:


AntiSamy as = new AntiSamy();
CleanResults cr = as.scan(suspeito);
String limpo = cr. getCleanHTML()

É considerada boa prática também purificar a saída dessas strings, por precaução. Com JSP, isso é muito fácil:

<c:out value="${suspeito}" escapeXml="true" />

Conclusão

XSS é um problema real e muitas aplicações estão vulneráveis. Samy atacou o MySpace em 2005 e conseguiu 1 milhão de amigos. A busca do Google tinha as falhas do UTF-7 comentadas acima em 2005. Apoiadores do Firefox sequestraram as maiores comunidades do Orkut em 2005 e mudaram os logos para o do Firefox. Eleitores de Hillary Clinton redirecionavam visitantes do site de Barack Obama para o site de sua adversária nas prévias da eleição americana em abril desse ano. E milhares de outros casos públicos.

Proteja sua aplicação!

Referências

Arquitetura e Design de Projetos Java

Por Paulo Silveira em 01/08/07

Hoje em dia são tantos os design patterns, padrões, frameworks e boas práticas, fica confuso tomar uma decisão. Como devemos desenhar nossas classes? Usar herança ou composição? Injeção de dependências? Webservices, RMI ou um simples arquivo XML? JDBC, JPA ou Hibernate? Devo usar EJB? Quando preciso e como faço um cluster?

Depois de um longo preparo da ementa, exercício e de como abordar tantos tópicos, trazemos a público um novo treinamento, o FJ-91, focado em arquitetura e design de projetos Java. O treinamento passa pelo uso correto da orientação a objetos, design de classes (patterns, domain driven design, componentização), frameworks e especificações, além de Web 2.0 e SOA.

Arquitetura e Desgin de Projetos Java



Os exercícios são apresentados de uma maneira bem diferente: fazemos checkout de inúmeros projetos construídos para este treinamento, com o objetivo de analisar o código, debater, melhorar, e testar os diferentes frameworks e arquiteturas. Desde exercícios simples como trocar herança por composição, até rodar uma aplicação com EJB em cluster. Além de conhecer muitos dos frameworks e novas tecnologias, o intuito é que as pessoas saiam com uma capacitade crítica aguçada para uma tomada de decisão.

Apesar de não ser o foco, cada capítulo apresenta testes simulados para a certificação Sun Certified Enterprise Architect, e também exercícios de modelagem e debates sobre as decisões tomadas, passando pelas três etapas da SCEA. Apesar dessa certificação ser bem antiga e ter um conteúdo ultrapassado em alguns quesitos, os outros tópicos abordados pelo treinamento estão bem mais próximos do Java EE 5.0, o que o torna qualificado para uma possível atualização da prova.

Ao final do treinamento ainda há um capítulo dedicado a tópicos sobre desenvolvimento e metodologias. Alguns papers clássicos são debatidos, como o Silver Bullet e o Mythical Man Month, além dos testes unitários e de aceitação. Ufa! 40 horas de muito trabalho.

Flex2 e VRaptor

Por Nico Steppat em 07/05/07

Flex2 (SDK) é OpenSource, razão suficiente para mostrar um pequeno exemplo como usar Flex2 com VRaptor. Vamos criar um página de login e uma lógica que verifique os dados no Servidor.

O que é Flex2?

Adobe Flex2 é um framework para criar aplicações ricas que rodam no browser. Flex2 é baseado no Flash que deve ser conhecido pelas interfaces bonitas e altamente interativas. Ele estende o Flash com um modelo de programação mais versátil e completo.

Flash Player

Para rodar uma aplicação Flex2 é preciso um plugin (flash player) para o browser. Ele funciona semelhante a JVM e abstraí todos as diferenças e incompatibilidades entre tipos e versões do browser.

Flex2 SDK

Para desenvolver uma aplicação Flex2, temos que baixar o Flex Software Development Kit ou SDK que, como eu mencionei é OpenSource. Com ele vem as ferramentas (como o compilador) e as bibliotecas básicas para criar uma aplicação.

Baixe o Flex2 SDK e descompacte-o. Na pasta bin você encontra o executável mxmlc, o compilador, que nós usaremos.

A primeira classe com Flex2/Actionscript

A linguagem do flex se chama ActionScript sua sintaxe é bem parecida com a do Java. Também tem package, import, construtores e métodos (que se chamam funções).

Vamos criar uma classe que representa nosso modelo na página de login ou seja uma classe Usuario com dois atributos, login e senha. Uma diferença é a palavra-chave “var” para definir variáveis e “function” para construtores/métodos. Além disso, o tipo da variável e o return type do método vem depois da declaração:

package modelo{
       public class Usuario {

               // class fields
               private var login:String;
               private var senha:String;

               /**
               * Constructor with parameters
               */
               public function Usuario(login:String, senha:String) {
                       this.login = login;
                       this.senha = senha;
               }

               public function getLoginParameters():Object {
                       return {"usuario.login"this.login, "usuario.senha" this.senha};
               }

               public function toString():String {
                       return "Login: " this.login + ", Senha: " this.senha;
               }

       }
}

Parece uma mistura do java e javascript. Salve a classe num arquivo Usuario.as numa pasta chamada modelo.

Adobe Flex Builder é uma IDE paga (baseada no eclipse) que ajuda na criação das classes e componentes visuais.

A interface gráfica

Os componentes gráficos são definidos num arquivo xml de forma declarativa. Para criar um item num formulário para inserir o login, podemos usar:

<mx:FormItem label="Login">
      <mx:TextInput id="loginInput"/>
</mx:FormItem>

Login, Senha e um botão seria:

<mx:HBox>
    <mx:FormItem label="Login">
        <mx:TextInput id="loginInput"/>
    </mx:FormItem>
    <mx:FormItem label="Senha">
        <mx:TextInput displayAsPassword="true" id="senhaInput"/>
    </mx:FormItem>
</mx:HBox>
<mx:Button  label="login" click="sendLogin(loginInput.text,senhaInput.text);"/>

Scripts

Observe que nós usamos um evento no botão, semelhante ao Javascript. Aqui chamamos um função sendLogin( .. , .. ) com os parâmetros do login e senha. Dentro do xml podemos definir uma área para nossos funções. Basta abrir :

<mx:Script>

<![CDATA[

	public function sendLogin(login:String, senha:String):void {
		//cria modelo
		var usuario:Usuario = new Usuario(login,senha);
		//chamada http aqui
	}

]]>

</mx:Script>

Definimos a interface gráfica e um método/função para ser chamado quando o botão “login” for apertado. Falta programar a chamada http, mas vamos primeiro criar a lógica no servidor com VRaptor.

Lógica com VRaptor

Usei o blank-project do VRaptor para instalar rapidamente um projeto web pré-configurado no Eclipse.

A classe UsuarioLogic é bem parecida com a do primeiro exemplo na página principal do vraptor. Ela simula um login de uma usuario num sistema. Se for um login válido, ela devolve “ok” caso contrário “invalid”.

@Component
public class LoginLogic {

  private String autenticado = "invalid";

  @Remotable
  public void check(Usuario usuario) {

    if(usuario == null){
      return;
    }

    //simula login
    if("johann".equals(usuario.getLogin()) &amp;&amp; "12345".equals(usuario.getSenha())) {
      System.out.printf("%s é valido!", usuario.getLogin());
      this.autenticado = "ok";
    }
  }
  //ejetando "autenticado" no formato JSON
  public String getAutenticado() {
    return this.autenticado;
  }
}

e o modelo:


public class Usuario {

    private String login, senha;

  //getters e setters
}

JSON

@Remotable muda o comportamento padrão do VRaptor e devolve todos os dados ejetados (pelo getters) no formato JSON.

Por exemplo, acessando o servidor pela lógica no contexto “flex”:

http://localhost:8080/flex/login.check.ajax.logic?usuario.login=johann&usuario.senha=12345

devolveria a resposta no formato JSON:

{"autenticado":"ok"}

Chamando a lógica com flex

Vamos voltar ao flex, e programar a chamada http. Para isso o flex oferece um objeto HTTPService que pode ser declarado no xml do flex:

<mx:HTTPService
	id      = "service"
	method  = "POST"
	rootURL = "http://localhost:8080/testes/"
	result  = "onSuccess(event)"
	fault   = "onError(event)"
/>

O importante é o atributo id, com ele podemos acessar o objeto HTTPService dentro do script. O método de callback “onSuccess” será automaticamente chamado depois do request, “onError” quando um erro acontecer. O princípio dos callbacks é também usado no javascript/ajax. Então voltando à função sendLogin, podemos fazer a chamada completa.

Corelib

No método onSuccess(event) converteremos a resposta Http para um objeto JSON. Por padrão o flex (ainda) não sabe lidar com JSON, por isso temos que disponibilzar uma biblioteca que dará essa possibilidade . A corelib do flex2 vem com suporte para JSON, e tem que ser baixado separadamente. Depois de descompactar, adicione o arquivo corelib.swc da pasta bin na pasta lib do Flex SDK.

Script completo

Finalmente o script intereiro que usa a classe Usuario, o HTTPService com os métodos de callback e a classe JSON da corelib:

<mx:Script>

<![CDATA[

	import mx.controls.Alert;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.events.FaultEvent;
	import mx.utils.ObjectUtil;
	import mx.rpc.http.HTTPService
	import com.adobe.serialization.json.JSON;
	import modelo.Usuario;

	public function sendLogin(login:String, senha:String):void {
		//cria modelo
		var usuario:Usuario = new Usuario(login,senha);

		//seta o url
        service.url = "login.check.ajax.logic";

		//faz a chamada passando os parâmetros
        service.send(usuario.getLoginParameters());
    }

    public function onSuccess(event:ResultEvent):void {

		//cria String baseado no resultado
		var rawData:String = String(event.result);
		//cria um objeto json
		var respostaNoFormatoJSON:Object = JSON.decode(rawData);

		//login ok?
		if(respostaNoFormatoJSON["autenticado"] == "ok") {
			Alert.show("Bem vindo!");
		} else {
			Alert.show("Usuário não existe");
		}
    }

    public function onError(event:FaultEvent):void {
        Alert.show(ObjectUtil.toString(event.fault));
    }

]]>
</mx:Script>

Compilação dos arquivos flex

O xml todo (com script e interface gráfica) deve estar num arquivo login.mxml. Temos a seguinte estrutura:

login.mxml
modelo/Usuario.as

Execute na linha de comando usando o compilador do flex (que está na pasta bin do sdk):

...pasta-para-flex-sdk/bin/mxmlc login.mxml

Isso vai criar a aplicação ou seja um arquivo login.swf.

Rodando no servidor

O login.swf deve estar no servidor, você pode abrir o login.swf localmente mas a chamada Http acaba num security exception (é bom para testar o método onError(..)).

No nosso exemplo:

http://localhost:8080/flex/login.swf

Toda configuração do servidor é padrão tomcat/servlet.

Download

Disponibilizo o pequeno exemplo como download

Ajax no VRaptor: JSON da maneira fácil

Por Guilherme Silveira em 08/11/06

Vamos falar um pouco de web antes que o Paulo Silveira transforme esse blog em um livro de Hibernate!

O Fabio Kung deu a idéia de usar JSON para fazer a estrutura básica de Ajax do VRaptor. O Paulo, que detesta(va) trabalhar com JavaScript e interfaces com o usuário, gostou bastante da maneira simples de se representar objetos com JSON. Ele correu atrás de diversas bibliotecas como a JSON-tools e a JSON-lib mas achou que uma dependência apenas para isso seria muita coisa, já que não haveria a necessidade de consumir JSON como Java, apenas produzir. Ele encontrou um código na internet bem simples, mas quando foi usar descobriu uma série de testes que falhariam, então ele, juntamente com o Nico Steppat, mexeu e criou o próprio JSONWriter do VRaptor, junto com um longo test case.

JSON é uma notação simples para definir uma variável em JavaScript que pode ser facilmente traduzida para um objeto de outras linguagens. Muitos frameworks para AJAX, como o Dojo e o Prototype, consomem mensagens JSON. E agora no VRaptor, dada uma simples classe como essa:

@Component
public class ContatoController {

        private List<User> users = new ArrayList<User>();

        @Remotable
        public void lista() {
                // puxaria do banco
                users.add(new User(1,"Paulo"));
                users.add(new User(2,"Guilherme"));
        }
        
        public List<User> getUsers() {
                return users;
        }
}

Basta você anotar o método como @Remotable e acessar contato.list.ajax.logic pela URL, que o resultado será:

{"users":[{"nome":"Paulo","id":1},{"nome":"Guilherme","id":2}]}

Pronto para ser consumido por um browser! Você pode ver no site mais detalhes sobre o AJAX com o VRaptor.

O Paulo ficou empolgado com a remotabilidade, e agora está implementando o RESTful do VRaptor da mesma maneira: contatos.lista.xml.logic vai te renderizar os mesmos objetos só que em XML! Já está no CVS e estará presente uma versão básica na versão 2.2.4 (assim como integração com Spring). Isso será não só útil para expor serviços, mas também para integrar seus componentes VRaptor com consumidores de XML como o Adobe Flex e o OpenLaszlo. O próximo passo é aceitar as requisições XML e JSON, não só apenas produzi-los.

Dei hoje uma palestra sobre esse assunto no SouJava, fazendo analogias com SOA e Service Component Architecture que o Paulo tanto elogia no Apache Tuscany. Ele quer dirigir o desenvolvimento do VRaptor para esse lado: poder expor facilmente seus componentes web como serviços, facilitando a futura integração e manutenção, dois pontos que nós desenvolvedores sofremos muito atualmente com os sistemas legados.