Protegendo sua aplicação – Mini Livro

Tipos de ataques e sugestões para evitá-los

Vamos detalhar agora sobre ataques famosos que podem acontecer e como fazer para proteger nossos projetos. Infelizmente em pouco tempo essa lista vai estar desatualizada, pois o hacker sempre estará um passo a nossa frente… Sempre!

SQL Injection

Creio que esse é o ataque mais famoso e muito utilizado. Podemos considerar que um projeto que está vulnerável a esse ataque precisa urgentemente de alterações em seus códigos e seus desenvolvedores também necessitam de um treinamento básico sobre segurança.

Assim como esse erro é um erro bobo de acontecer, para evitá-lo é muito simples.

Veja o código a seguir:

public Customer findCustomer(String customerName)throws Exception {
    try {
        Connection conn = null;
        String url = "jdbc:mysql://133.144.5.177:4405/";
        String dbName = "project";
        String driver = "com.mysql.jdbc.Driver";
        String userName = "root";
        String password = "root";
        try {
            Class.forName(driver).newInstance();
            conn = DriverManager.getConnection(url + dbName, userName, password);

            Statement st = conn.createStatement();
            String query = "SELECT * FROM  customer where customer_name=" + customerName;
            ResultSet res = st.executeQuery(query);

            Customer customer = buildCustomer(res);
            return customer;
        } catch (Exception e) {
            throwDataBaseError(e);
        }
    } finally {
        conn.close();
    }
}

O problema está justamente quando temos a concatenação de String: “… customerName=” + customerName. Esse código funciona perfeitamente se o usuário escrever apenas o nome dele como é devido: José. Agora, e se o hacker colocar como nome dele o seguinte valor: José’ or ‘Maria’. O que aconteceria? Seria retornado o cliente José e Maria ao mesmo tempo. O que aconteceria se ao invés de colocar “or Maria” fosse feito um comando SQL como delete ou update? Todos os usuários existentes no projeto seriam retornados. Uma grave falha de segurança que poderia acontecer, mas que pode ser facilmente solucionada com o código abaixo:

PreparedStatement  preparedStatement = conn.prepareStatement("SELECT * FROM  customer where customer_name=?") ;

preparedStatement.setString(1, customerName);

Agora está sendo utilizada a classe PreparedStatement para a consulta, e ela não entenderá o texto José’ or ‘Maria’ como comando de consultas mas sim como um texto simples.

E por mais simples e funcional que o ataque aparenta ser, mais ainda simples é o modo de como evitar, grandes empresas/instituições já tiveram dados roubados por causa desse ataque. Grandes quais? Governo Americano, Sony, Nokia, Linkedin, Yahoo… E isso desde o ano passado até o dia de hoje que fomos informados pela mídia. Na URL a seguir é possível encontrar uma listagem de grandes empresas que sofreram com esse ataque: http://codecurmudgeon.com/wp/sql-injection-hall-of-shame/.

JPQL Injection e HQL Injection

Existem pessoas que se acham seguras por utilizar o JPA (ou o Hibernante puro). Saiba que essa sensação de segurança é inválida e você estará sujeito a um ataque. A JPQL abaixo poderia sofrer com injeção:

String queryText = “select c from Customer c where c.name =” + customerName;

Note que o mesmo problema de concatenar String acontece também com JPA/Hibernate. Para solucionar esse problema com JPA basta utilizar parâmetros na consulta, assim como feito com JDBC:

String queryText ="SELECT c FROM Customer c where c.name = :name";

TypedQuery<Customer> query = em.createQuery(queryText, Customer.class);

query.setParameter("name", customerName);

List<Customer> customers = query.getResultList();

Não importa a tecnologia que você está utilizando para acessar o DB, sempre tenha em mente concatenar String é muito perigoso.

Cross-Site scripting (XSS)

Esse tipo de ataque acontece quando os dados enviados ao projeto não são tratados. Imagine um input onde o usuário pode salvar no banco de dados seu nome. Um usuário sem más intenções digitaria o nome, “José” por exemplo, e o projeto se comportaria sem problemas ao exibir o nome dele.

Imagine agora que o um hacker ao invés de escrever o nome dele, simplesmente escreveria algo como: <script>alert(‘uai?’)</script>. O que aconteceria quando o nome desse usuário fosse listado na página com o comando: ${usuario.nome}? O script inserido pelo usuário no lugar do nome seria executado pelo browser, pois ao invés de exibir um nome ele estaria escrevendo na página um comando javascript.

É exatamente desse modo que funciona o XSS, injetando código Javascript em seu projeto e fazendo com que seu projeto execute esse código para diversas outras pessoas. Um exemplo disso aconteceu com o Twitter onde pessoas começaram a “twittar” coisas sem querer (http://status.twitter.com/post/1161435117/xss-attack-identified-and-patched).

Existem diversos tipos de XSS: persistente, não persistente, refletido, etc. Não veremos como cada um funciona, mas veremos na prática como resolver esse problema independente do tipo do ataque.

O primeiro pronto a se tratar para esse tipo de problema é justamente a hora de exibir as informações para o usuário. Se utilizarmos apenas ${texto}  para exibir as informações estaremos sujeitos ao ataque; o browser pegará o valor do ${texto} e exibirá para o usuário como se fosse um código HTML; caso o valor vindo seja um script javascript esse script será executado normalmente. Para evitar esse primeiro problema é simples, você poderia utilizar a função de ‘escape’. Se fosse no JSF, poderia ser feito como:

<h:outputText value=“#{usuario.nome}” />

E para os que trabalham com Struts, SpringMVC, Stripes ou qualquer outro framework ActionBased bastaria utilizar o código abaixo para evitar o ataque XSS, o detalhe é que apenas a biblioteca core JSTL foi utilizada:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c: out value=“${usuario.nome}” />

Com a simples solução acima já seria possível evitar o problema do XSS, e nenhum Javascript malicioso seria executado.

E quando seu front end não está usando nenhum framework como SpringMVC ou JSF? Nesse caso uma boa ajuda seriam frameworks que existem com essa função.

É possível utilizar utiliza frameworks Javascript que ajudam na hora de tratar uma String:

Outra opção também seria tratar o valor enviado em classes Java. O framework abaixo é uma boa solução:

E caso seja da vontade da equipe tratar o input de modo manual, bastaria criar um Filter JEE e analisar as Strings presentes no request. Caso algum comando Javascript seja encontrado bastaria tratar o input do modo desejado.

Brute Force Attack

Esse tipo de ataque é quando um hacker que descobrir determinada informação por meio de diversas tentativas.

Imagine que um hacker sabe que existe o usuário “jose.de.arimateia” cadastrado no projeto. O hacker tentaria diversas senhas ou diversas combinações de letras para tentar descobrir a senha válida. Um usuário chamado “jose.de.arimateia” talvez seja difícil ter em seu projeto, mas e um usuário chamado “admin”, “administrador”, “root”, etc.

Um hacker poderia fazer um projeto que tentasse senhas como: a, ab, abc, abcd… Um hacker tem todo tempo do mundo para deixar o código rodando e, eventualmente, descobrir a senha.

Outro modo interessante de é que é possível encontrar sites que mostram quais são as senhas mais utilizadas no mercado:

Sabendo quais são as senhas mais utilizadas no mercado um hacker poderia simplesmente tentar essas senhas. Caso não tenha sucesso ele poderia tentar outro usuário até encontrar um. Um hacker que descobre o padrão do nome de usuário das empresas poderia facilmente realizar um ataque para cada funcionário. Como descobrir a lista de funcionários de uma empresa? Linkedin seria uma boa fonte de pesquisa. Todos os funcionários não estarão listados no Linkedin, mas basta que apenas 1 funcionário tenha sua senha nas listas dos links acima para que a segurança seja quebrada.

O projeto que utilizar uma criptografia fraca em seu banco de dados estará sujeito a um maior dano caso seus dados sejam roubados. Imagine que um hacker consiga roubar todo os logins e suas respectivas senhas criptografadas com MD5. MD5 hoje não é uma criptografia segura, e pode ser facilmente quebrada. Existem sites que facilmente mostram o valor de um MD5: http://www.md5online.org/md5-decrypt.html. É possível também encontrar diversos sites que listam senhas em MD5 já encontradas na net: http://forum.md5decrypter.co.uk/topic870–md-hashed-passwords-list.aspx.

Algumas ações podem ser tomadas para evitar um Brute Force Attack realizado em seu projeto:

  • Adicionar no site algum tipo de segurança de validação do usuário, algo como um CAPTCHA
  • Definir uma quantidade de tentativas para logar. Se o usuário errar 5x a senha, ele não poderá mais logar por um dia ou até entrar em contato com o suporte
  • A equipe de infra pode identificar se determinado IP está com muitas tentativas de login e bloqueá-lo por determinado tempo.
  • Aumentar o tempo de retentativa de login. No primeiro erro o usuário já pode tentar novamente. Após o segundo erro, ele terá que esperar 5s, etc.

Inclusive esse é um tipo de ataque que pode vir junto do DoS (ou DDoS) que veremos mais a frente.

Man In The Middle

Man In The Middle é quando uma pessoa consegue interceptar uma requisição feita a um servidor. Imagine que um usuário fará uma requisição ao servidor e um hacker conseguirá interceptar os pacotes enviados e ver o que foi enviado ou até mesmo alterar.

Para evitar esse tipo de ataque basta utilizar SSL em suas conexões. Sabe quando você acessa um site e no endereço aparece escrito HTTPS? Essa conexão segura serve para evitar que alguém fique entre o servidor e o usuário. Essa proteção é feita no servidor e não no código.

XPath Injection

XPath Injection acontece quando dentro de um XML utilizado para validação de dados, uma informação maliciosa é adicionada. Imagine que o XML abaixo é utilizado para realização do login:

<user>
    <username>uai@google.com</username>
    <password>ahuid98317</password>
</user>

Imagine que o comando a seguir é utilizado para realização do login do usuário: //users/user[username/text()=’&LOGIN&’ and  password/text()=’&PASSWORD&’ ]. Note que a partir de agora o mesmo problema do SQL Injection pode acontecer. Alguém poderia simplesmente passar o login como José de Arimatéia’ or ‘1=1’ que o restante da consulta será ignorado. Note que a consulta pararia sempre na condição 1=1 que sempre retornaria true e o password nunca seria validado.

Para evitar esse tipo de erro sempre trate o valor enviado pelo usuário. Não importa quem seja o usuário do projeto, o melhor é nunca confiar na informação enviada pelo usuário.

Outra solução seria utilizar o a biblioteca XQuery; ela funciona como o PreparedStatement ou a Query do JPA. Com a biblioteca XQuery é possível evitar que códigos maldosos enviados pelo usuário não sejam processados.

Caso você quei-ra tratar manualmente os valores que estão chegando bastaria remover do request, enviado pelo usuário, os seguintes parâmetros/caracteres (e similares):

  • <
  • >
  • /
  • ‘ = “
  •  ‘
  • =
  • *
  • ?
  • /

LDAP Injection

Assim como os outros ataques de injeção vistos acima, esse ataque também visa inserir caracteres inválidos. A solução seria eliminar do request enviado pelo usuário valores que poderiam causar problemas. Veja a lista abaixo:

  • /
  • \
  • Espaço em branco no começo e fim do valor
  • #
  • <
  • >
  • ,
  • ;
  • +
  • *
  • (
  • )
  • u0000 Unicode NULL caracter

DoS ou DDoS

Você já viu na mídia aqueles tipo de reportagens: “Anonymous promete derrubar o facebook” ou “grupo hacker tira site do governo do ar”? Em geral são ataques DoS que significam Denial of Service ou DDoS: Distributed Denial of Service.

A cada requisição feita ao servidor uma sessão é criada e o ID dessa sessão é retornado ao usuário; quando esse usuário faz outra chamada ao servidor o ID da sessão é enviado novamente e o servidor consegue identificar que uma sessão já existe e que não será necessário criar outra. Agora imagine se 100 requisições sem ID de sessão chegam… O servidor criaria uma sessão para cada request que chegar e com isso teria 100 “espaços” na memória ocupados. E se começarem a chegar 100 requisições por segundo, quanta memória seria ocupada em questão de 30 segundos? Após algum tempo, seu servidor será derrubado por falta de memória por causa de todas as sessões criadas.

A solução para esse problema cabe muito ao pessoal da infra-estrutura e não a quem desenvolve o projeto. Eles poderiam desviar o fluxo de determinado IP ou faixa de IP para uma página estática que não cria Sessão. Se for um usuário válido ele clicará em um botão que o mandará para o projeto. Outra solução seria bloquear o IP do ofensor.

Slow DoS

Já o Slow DoS ao invés de enviar diversas requisições por segundo, ele envia requisições bem devagar. A entrega de pacotes enviados demora muito e isso faz com que o servidor fique com canais abertos esperando a entrega de todos os pacotes; uma vez que muitos canais estão sendo abertos, e nenhum canal sendo fechado, o servidor parará de responder.

Novamente uma solução que cabe ao pessoal de infra-estrutura agir. Eles podem ver o request que está demorando muito para chegar, até mesmo acima de uma determinada média, e abortar essa requisição. Poderão também bloquear o IP do ofensor.

31 thoughts on “Protegendo sua aplicação – Mini Livro

  1. Achei muito positiva a iniciativa… acompanho o blog sempre que posso como maneira de estudo e sempre achei que isto é algo que falta na visão dos desenvolvedores e/ou analistas, porque impactam em outras áreas e medidas pequenas ajudam no que circunda uma aplicação.

    • Henrique, boa tarde.

      Realmente é difícil ver o assunto segurança em blogs ou foruns.

      Ultimamente li muito material sobre segurança e resolvi compartilhar. [=

      Obrigado pelo apoio! =D

  2. Parabéns pela iniciativa, Hebert!! Sempre tenho visto os posts e são sempre sobre um tema atual, interessante e este, um tema que pouco se ver falar. Vou terminar de ler, mas me parece bem interessante. Mais uma vez, parabéns!

  3. Parabéns por mais este excelente post!!!
    Mas eu gostaria de saber,e tenho certeza que outras pessoas que acompanham seu site também é quando teremos um livro da casa do codigo – EJB 3.2 Eficaz? rsss, já tenho a JSF Eficaz, JPA Eficaz.

    • Jivago, boa tarde.

      Muito obrigado pelo apoio, fico feliz por saber que estou ajudando.

      Quanto ao livro infelizmente não depende só de mim, mas do pessoal da casa do código também. [=

      Até mais.

  4. Parabéns Hebert :D os seus conteúdos são muito top :D

    E eu feliz aqui com meus 11k acessos do meu blog hauahuahua
    mas não crio nada, apenas posto soluções de exceptions/erros
    e tradução de alguns artigos que acho útil :D

    é isso ai… continue com o ótimo trabalho :D

    Abraços!

    • Gustavo, boa tarde.

      Obrigado pelo apoio.

      Eu vejo qualquer ajuda importante.

      Eu também fiquei feliz da vida quando fiz 10k de visitas algum tempo atrás.

      O importante é não desanimar. [=

      Até mais.

    • Jeferson, boa tarde.

      Obrigado pela visita, e desculpe a demora em responder. Estive muito ocupado nesse último mes.

  5. Parabéns pelo excelente post hebert, esse trabalho que você faz aqui no blog de compartilhar conhecimento é fantástico!

  6. Fiz um teste utilizando XSS, salvei como Teste
    E não funcionou =/

    Aqui não teve como por o link direito, mas eu fiz um link e não funcionou =I

    • Marcos, boa tarde.

      Nesse caso você não colocou a URL, por isso não apareceu direito. Acredite ou não, aqui para mim o Teste está parecendo diferente. [=

      Obrigado pela visita.

      • Boa Noite Hebert ,
        Aqui no blog ficou como link, mais na minha aplicação não ocorreu isso , ficou normal e até um script não rodou.
        Mas eu confio no que você diz e me atentarei com isso nas próximas vezes.

        Sensacional esse mini-livro, já li todos os livros e mini-livros seus[ tenho eles impressos para auto-ajuda].

        Impossível destacar qual o melhor, são todos sensacionais!

        Sou teu fã de carteirinha assinada tenho todas as coleções dos mini-livros e dos EFICAZES ( Jpa e JSF ), estou muito ansioso para o próximo lançamento do EFICAZ!.
        Deus continue te dando sabedoria, peço isso diariamente.
        Quero ser igual a você, com todo esse conhecimento algum dia, meu ídolo!

        Abraços, meus parabéns e até a próxima !

  7. Execelente mini livro, através dele estou podendo adquirir uma bela noção de segurança em aplicações que,particularmente, é uma área que me fascina e que é de suma importância, pois ataques especializados estão se tornando cada vez mais frequentes.

    Baixando o PDF para consulta posterior, mas voltarei a visitar esse site mais vezes!

  8. Não costumo comentar em blogs, mas nesse caso é preciso.
    Parabéns pelo trabalho cara, obrigado por compartilhar o seu conhecimento com a comunidade!

  9. Inacreditável pois quando aprendemos e lemos sobre o assunto de brechas de segurança e erros de programação, a primeira imagem que vem em mente é um estagiário criando seus primeiros códigos ou um estudante aprendendo sobre alguma linguagem e que saiu vendendo seus sites/projetos sem ter o conhecimento mínimo necessário, mas então vemos exemplos de erros e brechas da Microsoft, NASA, Yahoo, Nasdaq, governos entre tantos outros, é no mínimo cômico :D . Gostei muito deste seu mini livro, tem uma visão macro de muitos detalhes imprescindíveis para a sólida construção de um software. Parábens!

  10. Olá. Parabéns pelo blog. São ótimos os tópicos: atuais e revelantes. Já adicionei ao meu leitor de feeds.

    Fiquei com uma dúvida ao ler seu mini-livro e gostaria de ouvir sua opinião. E quanto ao uso de senhas e usernames em arquivos XML, como o persistente.xml do JPA? O que você recomenda? Criptografar o arquivo? E quanto à colocar senhas no próprio código fonte?

    Obrigado. Paulo.

    • Paulo, boa noite.

      Primeiro, me perde a demora em responder. Estou muito pegado no trabalho, para você ter idéia, estou te respondendo dele enquanto um deploy não termina.

      Honestamente não recomendo colocar senha nem no persistence.xml e nem no código. Para mim o melhor local para se colocar a senha é na configuração de pool de conexão que pode ficar dentro do servidor. Ao configurar o pool de conexão (ex.: tomcat, jboss, etc) você pode colocar a senha criptografada. A vantagem dessa abordagem é que você não precisará fazer um novo deploy da aplicação apenas por uma senha trocada.

      Espero ter ajudado, obrigado pela visita e pelo apoio.

  11. Outra dúvida: e quanto ao uso do atributo “rendered” do JSF para esconder informações importantes? Por exemplo, quando alguém esconde de um usuário comum, alguns itens de menu que só devem ser vistos por um usuário cadastrado no sistema.

    • Paulo, boa noite.

      Eu recomendo sempre esconder, mas ainda assim bloquear o acesso no código. Eu penso que se o usuário não deve ter acesso a informação, ela não deve nem ser enviada a tela.

      Espero ter ajudado. Obrigado pela visita.

      • Aí reside a minha dúvida: quando uso o “rendered”, os dados que não devem ser vistos são enviados na resposta da requisição e os mesmos são escondidos no browser do usuário (via JS, por exemplo)? Ou o JSF detecta, no lado do servidor, que os dados não devem ser enviados, altera a árvore de componentes e envia a resposta já omitindo esses dados? Obrigado.

        • Paulo, boa noite.

          Vou te dar uma resposta que você não esperava ouvir: “Por que você não faz o teste e coloca a resposta aqui? Esse teste é fácil de reproduzir. Após a página ser exibida, olhe o código fonte. Coloque em seu código códigos como System.out.println(“passou aqui”) para você saber por onde sua chamada passou”.

          Obrigado pela visita.

Leave a Comment