http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Sumário No que se baseia segurança? .................................................................................................... 3 Publico Alvo ............................................................................................................................... 5 Ataques Internos.................................................................................................... 5 Ataque interno proposital ....................................................................................... 6 Conclusão.............................................................................................................. 6 Um bom hacker sempre tem tempo ......................................................................................... 7 Cuidado com a informação retornada .................................................................... 7 Cuidado com o tamanho da mensagem retornada .............................................. 10 Firewall/SSL não faz mágica................................................................................ 10 Tipos de ataques e sugestões para evitá-los........................................................................... 11 SQL Injection ....................................................................................................... 11 JPQL Injection e HQL Injection ............................................................................ 12 Cross-Site scripting (XSS) ................................................................................... 13 Brute Force Attack ............................................................................................... 14 Man In The Middle ............................................................................................... 16 XPath Injection .................................................................................................... 16 LDAP Injection ..................................................................................................... 17 DoS ou DDoS ...................................................................................................... 18 Slow DoS ............................................................................................................. 18 Cuidado com os dados ............................................................................................................ 19 Protegendo a entrada de dados........................................................................... 19 Protegendo a saída de dados .............................................................................. 19 Cuidados com o “Client Side”.................................................................................................. 22 Fique atento a URL.............................................................................................. 23 Testes Técnicos................................................................................................... 24 Validações ............................................................................................................................... 24 Validando dados .................................................................................................. 24 Cuidado com arquivos ......................................................................................... 25 Sempre dê o menor privilégio possível ................................................................................... 25 Trate os erros do projeto ........................................................................................................ 27 Cuidados com bibliotecas de terceiros ................................................................................... 28 Versão do Projeto.................................................................................................................... 29 Preste atenção com o LOG ...................................................................................................... 29 Separe seu projeto das camadas ............................................................................................ 30 Comentários nem sempre são saudáveis................................................................................ 31 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Sempre valide seu código........................................................................................................ 31 Tenha um CheckList ................................................................................................................ 32 Cuidado com a equipe de TI .................................................................................................... 32 Exposição dos dados ........................................................................................... 33 Cuidado com o código escrito .............................................................................. 34 Futuro ex-funcionário.............................................................................................................. 34 Code Review / Pair Programming ........................................................................ 34 Fique atento a terminologia ................................................................................. 35 Proteja a senha do modo correto ........................................................................................... 35 Boas práticas para controle de acesso .................................................................................... 36 Esconda o botão/link, mas proteja o código ......................................................... 36 Conheça a necessidade do seu usuário .............................................................. 37 Sempre oculte ..................................................................................................... 37 Políticas de Segurança............................................................................................................. 38 Evitando falhas de códigos e/ou frameworks ......................................................................... 39 Não exponha tecnologias desnecessariamente ................................................... 39 Nunca misture os tipos ........................................................................................ 39 Utilize chaves nos “IFs”........................................................................................ 39 Inteiros com Flutuantes........................................................................................ 40 Sempre programe defensivamente ...................................................................... 40 Por hoje é só ............................................................................................................................ 42 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro No que se baseia segurança? Infelizmente falar de “segurança de projetos” não é simples, esse termo é um termo muito amplo e é possível encontrar diversas definições. Umas definições interessantes são da Microsoft (links no final) sobre o que abranger quando falamos de “segurança de projetos”. Abaixo podemos listar as bases da segurança de projetos citadas pela Microsoft (haverá comentários e linhas a mais que eu escrevi abaixo): Autenticação: Quem é você? Essa ação determina se a chamada ao nosso projeto vem de uma fonte conhecida. Uma fonte conhecida poderia ser uma pessoa, um celular, um browser, um hacker, etc. Existem diversos projetos que não necessitam de um login, por exemplo: Google, uaiHebert.com, etc. Não é só por que uma requisição está sem dados de login (usuário autenticado, login, senha, etc), que ela não pode ter um perfil conhecido. Para requisições de usuários não logados um perfil como NAO_LOGADO seria ideal. As vantagens de ter um perfil para quem não está logado seria: o Podemos ter uma linguagem em comum na hora de debates sobre o projeto, a seguinte frase poderia aparecer: “essa nova funcionalidade poderia ser acessada por um NAO_LOGADO?”. o O perfil NAO_LOGADO poderia ser filtrado em determinadas áreas do projeto: “Perfil NAO_LOGADO não poderá ter acesso a tela X”. o Em caso de auditoria poderíamos ter diversos registros de navegações salvos para alguém do perfil NAO_LOGADO. Autorização: Você pode fazer isso? Uma chamada que vem de um perfil conhecido (ou não no caso de usuários de perfil NAO_LOGADO) e que foi validada por um processo de autenticação, pode ou não realizar determinada ação. Um usuário poderia apenas ter acesso de leitura, enquanto um gerente poderia ter acesso as ações de CRUD do projeto. Falhas de autorizações poderiam levar a gravíssimos problemas, perda de dinheiro para a empresa, quebra de confiança para com o usuário, etc. Auditoria: Haverá quem fiscalize o projeto? O que será fiscalizado? Existem projetos que colocam todas as informações do projeto (dados do request, dados do usuário, etc) em um banco de dados/arquivos de texto e, ao acontecer algum problema, colocam algum funcionário para analisar aquela quantidade enorme de registros. Muitas vezes a enorme massa de dados causa preguiça/indisposição na hora de buscar algum problema, o que pode ocasionar erros na procura de falhas de segurança. Sempre deixar disponível para o auditor (seja um profissional em auditoria ou um desenvolvedor) as informações de um modo bastante direto e objetivo. Salvar as informações importantes em lugares separados é importante para conseguir analisar uma possível fraude, por exemplo, um cliente que alega que não solicitou a troca de plano e processa a empresa. Note que o trabalho de auditoria pode vir a ajudar na questão da segurança e na questão da evolução do projeto. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Confidencialidade: também conhecida como privacidade, confidencialidade é o conceito de somente ter acesso a determinada informação somente quem pode ter. Uma pessoa só poderá ver as fotos de outra se for permitido. Outra preocupação também é: os dados estão protegidos na hora do envio e do recebimento da informação? Estamos protegendo a informação de modo que ninguém no meio do caminho consiga roubar a informação? Veja a imagem abaixo: Qual a garantia que temos de que a informação enviada é a mesma recebida? O que precisamos fazer para que o “User Request Data” não seja interceptado? É preciso ter o cuidado de proteger as informações enviadas pelo usuário, não deixar que nenhum dado confidencial seja exposto. Integridade: A informação recebida está exatamente ao que o foi enviado? Imagine que uma pessoa, cheia de maldade no coração, interceptou um request enviado por um usuário e alterou o email enviado ([email protected]) para o email dele ([email protected]). A partir daí todos os comunicados que seriam recebidos pelo nosso usuário feliz iriam para o hacker do mal; uma vez que o hacker tenha em mãos os comunicados enviado e ele poderia simplesmente encaminhar o email para nosso usuário feliz e continuar com a farsa. É preciso sempre ter certeza de que a informação enviada chegue completa e sem alterações. Disponibilidade: a aplicação sempre deve estar disponível para requisições de chamadas confiáveis. Durante um ataque de DoS (veremos mais a frente) é preciso manter o serviço disponível para os usuários confiáveis e de algum modo impedir que o projeto falhe. Note que os conceitos vistos tratam os aspectos de como a aplicação deve se comportar, mas e com relação aos funcionários que trabalham com a aplicação? Como devemos tratar ataques internos? Que tipo de código pode prejudicar a segurança do nosso projeto? Todos os pontos vistos acima e as perguntas levantadas nesta página serão detalhadas mais a frente nesse post. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Publico Alvo Toda vez que um desenvolvedor for criar um projeto ou até mesmo aumentar a segurança de um projeto existente, é necessário levantar qual será o público alvo do projeto. Um projeto que é aberto para o mundo precisa ter mais cuidados do que um projeto que rodará em uma intranet sem acesso externo. Essa informação é necessária para um levantamento de requisitos mais aproximado da realidade. Um projeto que rodará apenas em uma Intranet inicialmente não teria a necessidade de uma proteção contra Brute Force ou XSS, por exemplo, no começo do projeto. Caso o projeto fique acessível para toda internet, seria necessário pensar em todas as possibilidades de ataques e o que fazer quando eles acontecerem. Ataques Internos É preciso sempre pensar que ataque interno pode acontecer. Podemos pensar em ataque interno em duas categorias: acidental e proposital. Um ataque interno acidental seria quando um usuário inexperiente poderia clicar em um arquivo zipado chamado “alterarSenhaDoBanco.exe”. O melhor jeito de tratar esse problema seria pensando: “que tipo de dano esse ataque me causaria”. Alguns pontos a se pensar são: A máquina do banco de dados e/ou servidor do projeto está exposta a um usuário inexperiente? Um usuário consegue fazer um ping ou acessar a máquina via FTP, SSH ou por pastas? A máquina tem todas as portas de comunicação abertas? Uma solução seria deixar habilitada, para todos os usuários do projeto, apenas a porta 80 ou 8080 ou a porta que realmente é utilizada. O projeto tem um local de backup em comum com usuários inexperientes? O ideal é ter ambientes separados para evitar que um hacker não copie dados do usuário e da aplicação. Imagine o dano que um virus “DELETE ALL” poderia fazer em seus backups. Da rede local é possível que qualquer um abra um túnel para outra rede? Uma solução para esse tipo de problema é: utilizar firewall para evitar que esses tipos de conexões não sejam facilmente iniciadas; usuário que não precisam de túnel não precisam desse recurso liberado. Se possível deixe o projeto em uma rede separada. O projeto em uma rede e ambientes separados dos demais usuários da empresa evitará ataques internos acidentais. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Ataque interno proposital Pode haver também o chamado ataque interno proposital. Esse tipo de ataque pode partir de um funcionário que está com raiva com a empresa, algum funcionário que quer tirar proveito de alguma situação ou até mesmo prejudicar outro funcionário. Um funcionário que não é do setor de TI, mas que pode entender de programação, poderia por exemplo, aumentar seu banco de horas apenas com um update; tudo que ele precisaria seria a URL do banco de dados e disparar um Brute Force Attack até encontrar uma senha válida. E você acha difícil alguém conseguir roubar a URL do banco? Bastaria ele puxar papo com alguém de TI, falar que está interessado em projetos + banco de dados e se mostrar simpático. Em pouco tempo o usuário maldoso estaria sentado ao lado de alguém de TI, observando tudo apenas para ‘aprender’ como é o dia a dia de alguém de TI. E facilmente ele conseguiria ver a URL de conexão e até mesmo ter acesso a senha. Proteja a TI de funcionários de outros setores. Só por que a pessoa é a dona da empresa, e não entende nada de TI, que ela precisa ter usuário e senha a todos os ambientes da empresa; caso você seja obrigado a dar acesso, usuário, senha a pessoas fora do setor deixe isso claro por emails, memorando ou papeis que deixem alguém ciente da responsabilidade. Assim você estará protegido contra problemas futuros de roubo de senhas ou uso indevido. Conclusão A vantagem de se determinar quem é o público alvo é que você terá idéia do que deve entrar no planejamento do projeto, e em qual etapa. Quando o projeto é acessado apenas de uma rede fechada, algumas features de segurança podem ser postergadas ou até mesmo ignoradas; uma proteção contra o ataque XSS (veremos ainda nesse post) poderia ser entregue nas etapas finais do projeto, por exemplo. Quando temos um projeto aberto ao mundo é preciso ter cuidado em sempre ter presentes proteções contra os ataques. Proteção contra XSS, por exemplo, seria primordial no começo do nosso projeto. Um projeto recém lançado que já apresenta problemas de invasões terá dificuldades em obter credibilidade e confiança do usuário. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Um bom hacker sempre tem tempo Certa vez enquanto eu participava de um curso sobre segurança ouvi a seguinte afirmação do especialista: “até mesmo a menor variação no número de bytes retornado na resposta de um request feito ao servidor será analisado por um hacker”. Um bom hacker terá a paciência de escovar os bytes retornados, HTTP Headers, campos escondidos e qualquer outra informação que possa ser válida. Analisando a afirmação acima é possível pensar no seguinte: “o que nossos projetos têm retornado aos usuários?” ou “quando uma RuntimeException acontece, qual a resposta é enviada ao usuário?”. Quando eu falo de resposta ao usuário eu não digo apenas o texto exibido, mas digo também sobre headers, campos escondidos, etc. É preciso estar atento a esses detalhes, pois um bom hacker vai gastar seu tempo investigando cada detalhe do seu projeto. Supondo um projeto onde apenas a tela de login seja possível acessar sem um usuário e ou senha válida, veja algumas coisas que um hacker poderia analisar ou tentar (veremos mais a frente): SQL Injection XSS Bytes recebidos Variação das mensagens recebidas Brute Force Attack Campos escondido Note que apenas com uma página diversos tipos de ataques e análises de dados podem acontecer. Cuidado com a informação retornada É preciso sempre analisar a informação que é retornada ao usuário. No começo da internet era muito comum encontrar a seguinte mensagem ao errar o usuário na hora do login: “usuário incorreto”; a mensagem vista poderia levar um hacker a tentar alterar o usuário até certar um, que seria quando a seguinte mensagem apareceria: “senha incorreta”. O problema agora é que um hacker já conseguiu ter um login válido ao nosso projeto, bastaria tentar diversas senhas até conseguir uma válida. O problema visto acima seria facilmente resolvido com a mensagem: “usuário e/ou senha inválidos”. Note que não foi preciso aumentar a proteção do código ou até http://uaihebert.com/protegendo-sua-aplicacao-mini-livro mesmo criar diversas regras de segurança. Um hacker nunca saberia se ele conseguiu ou não um login válido por causa da mensagem acima. Outro problema de mensagem retornada seria que, ao excluir um usuário, exibir um texto como: “Você não tem permissão para excluir um registro. Apenas usuário com o papel de ADMIN pode excluir”. É necessário mesmo que um usuário fique sabendo que existe o papel de ADMIN? Por que expor o modelo de negócio do projeto sem necessidade? Você poderia ter uma mensagem como: “Você não tem permissão para excluir” ou até mesmo “Não foi possível excluir o registro agora, caso o erro persista, entre em contato por email e informe o código 3345981UAI”. A vantagem da segunda opção é que você vai ter idéia de qual usuário está tentando fazer alguma ação ilegal, pois ele virá até você. Um exemplo que encontrei recentemente foi do jogo Candy Crush. Uma amiga ao jogar encontrou a seguinte mensagem de erro: Veja que foi exibido a URL que o aplicativo utiliza para fazer a conexão com o servidor. Era necessário mesmo? Por que um usuário precisa ver essa mensagem tão técnica? O que uma pessoa que entende alguma coisa de programação poderia http://uaihebert.com/protegendo-sua-aplicacao-mini-livro fazer com essa mensagem? Ele poderia simplesmente disparar diversas chamadas e encontrar falhas de segurança. Por curiosidade eu chamei a URL no browser e olha o que foi retornado: Qual a necessidade disso? Expor todos os métodos da classe? Se quando eu chamei a URL sem parâmetros toda essa informação me foi passada, o que aconteceria seu eu começasse a passar parâmetros na URL? Um bobeira de uma mensagem de erro não tratado pode causar graves problemas ao seu projeto. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Cuidado com o tamanho da mensagem retornada É preciso ter cuidado com o tamanho da mensagem retornada ao usuário. Imagine que toda vez que algum erro aconteça, o usuário será levada a uma tela que exista apenas o texto: “desculpe, aconteceu um comportamento inesperado”. Independente do erro o usuário sempre irá para a mesma tela com a mesma mensagem, ou algo bem próximo variando apenas uma pequena porção do texto. Apesar da solução de tela com uma mensagem ser uma ótima solução, um bom hacker analisará a quantidade de bytes retornados em cada resposta; com essa informação em mão ele poderá realizar diversos tipos de erros e testes para descobrir o que pode estar variando nos bytes retornados, em que caso ele poderia causar dados corrompidos no projeto ou até mesmo se ele conseguiria derrubar o projeto provocando erros. Um modo para tratar a mensagem retornada é sempre ter uma tela/campo padrão variando apenas o texto exibido, validar se os headers enviados são sempre os mesmos e sem nenhuma informação desnecessária. Firewall/SSL não faz mágica Existem pessoas que pensam que com um bom firewall e utilizando SSL (HTTPS na URL) já estão com seus problemas resolvidos, afirmar isso é um erro enorme. Firewall configurado corretamente pode impedir hackers de invadirem a rede, navegar no servidor, etc. Ao utilizar SSL (HTTPS) podemos evitar o ataque do tipo Man in the Midle (veremos na próxima página). São duas ferramentas muito boas pare evitar determinados tipos de ataque, mas existem diversos outros tipo que facilmente passariam por essas defesas: Injection (SQL, XPATH, LADP), XSS, dados incorretos enviados, falha em regras de negócio por código não corretamente programado, etc. Tome cuidado ao achar que a responsabilidade proteção do projeto deve ficar apenas na Infra. Creio que toda a equipe do projeto deveria ser envolvida quando o assunto é segurança. http://uaihebert.com/protegendo-sua-aplicacao-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 { 1 try { 2 Connection conn = null; 3 String url = "jdbc:mysql://133.144.5.177:4405/"; 4 String dbName = "project"; 5 String driver = "com.mysql.jdbc.Driver"; 6 String userName = "root"; 7 8 String password = "root"; try { Class.forName(driver).newInstance(); 9 conn = DriverManager.getConnection(url + dbName, userName, password) 10 11 Statement st = conn.createStatement(); 12 String query = "SELECT * FROM 13 ResultSet res = st.executeQuery(query); customer where customer_name=" + cust 14 15 Customer customer = buildCustomer(res); 16 return customer; 17 } catch (Exception e) { throwDataBaseError(e); 18 19 } } finally { http://uaihebert.com/protegendo-sua-aplicacao-mini-livro conn.close(); 20 } 21 22 } 23 24 25 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: 1 PreparedStatement preparedStatement = conn.prepareStatement("SELECT * FROM 2 3 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-ofshame/. 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: 1 String queryText = “select c from Customer c where c.name =” + customerName; cust http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 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: 1 String queryText ="SELECT c FROM Customer c where c.name = :name"; 2 3 TypedQuery<Customer> query = em.createQuery(queryText, Customer.class); 4 5 query.setParameter("name", customerName); 6 7 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/xssattack-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 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 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}” /> 1 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: 1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 <c: out value=“${usuario.nome}” /> 3 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: AntiSamy o https://www.owasp.org/index.php/Category:OWASP_AntiSamy_Project Coverity Security Library o https://github.com/coverity/coverity-security-library Outra opção também seria tratar o valor enviado em classes Java. O framework abaixo é uma boa solução: jsoup o http://jsoup.org/cookbook/cleaning-html/whitelist-sanitizer 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. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 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: http://www.telegraph.co.uk/technology/internet-security/10303159/Most-common-andhackable-passwords-on-the-internet.html http://www.cbsnews.com/news/the-25-most-common-passwords-of-2012/ 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/md5decrypt.html. É possível também encontrar diversos sites que listam senhas em MD5 já encontradas na net: http://forum.md5decrypter.co.uk/topic870–mdhashed-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 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 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: 1 <user> 2 <username>[email protected]</username> 3 <password>ahuid98317</password> 4 </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. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 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 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 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. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Cuidado com os dados É preciso ter todo o cuidado possível com os dados do nosso projeto. Basta que uma informação maliciosa entre em nosso projeto para que possamos ter problemas de segurança. Problemas também acontecem quando dados problemáticos são exibidos. Protegendo a entrada de dados “Nunca confie no usuário”! Essa frase deveria estar escrita em todo monitor de todo desenvolvedor. Proteger dados não significa apenas verificar se o usuário está tentando fazer algum tipo de Injection, mas significa também validação das regras de negócio. Imagine um aplicativo móvel que realiza a transações financeiras com cartão de crédito. O JSON enviado para confirmação de compra seria algo como: 1 { 2 “customerId”: “32”, 3 “creditCardId”: “446519”, 4 “productId”: “592-AAB”, 5 “value”: “42”, 6 7 “descount”: “5” } Veja que no código acima temos dados possíveis para realizar a compra de algum produdo. Se nosso projeto fosse utilizado apenas por usuários confiáveis, não haveria problema em receber essa informação e processar o pedido de compra. Como estamos partindo da premissa que não podemos confiar em qualquer informação enviada pelo usuário, o que garante que o customer de id 32 realmente tem o cartão de id 446519? O que aconteceria se o customer 32 utilizasse o creditCardId=155? Ou então, o que aconteceria se o request viesse com o discount = 50 ou 42? A compra sairia de graça? Ou seria necessário retornar dinheiro para o usuário? Para segurança de outros usuários e dos dados do projeto é sempre bom que toda informação enviada seja validada. Protegendo a saída de dados Por diversas vezes imaginamos que: “basta proteger a entrada de dados que estamos salvos de qualquer tipo de ataque”. Veja a imagem abaixo: http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Uma imagem que demonstra um servidor que acessa apenas o seu próprio banco de dados. Imagine que uma nova rotina será implementa onde o uaiServer buscará informações de um servidor de uma empresa parceira. O que não garante que o outro servidor que está sendo consultado não terá sofrido um ataque hacker? Você simplesmente estaria importando dados maliciosos de outros projetos para dentro do seu. E outra situação também poderia acontecer: http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Como visto acima é possível que outro projeto de sua empresa comece a chamar o mesmo banco de dados utilizado pelo seu projeto. O que não garante que dados maliciosos serão inseridos? É possível que o outro projeto tenha sofrido um ataque e agora está espalhando vulnerabilidades. Para evitar as situações listadas acima seria necessário tratar os dados enviados aos usuários seja em classe Java e/ou frameworks javascript e/ou taglibs como visto na página anterior. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Cuidados com o “Client Side” Infelizmente diversos projetos não dão a devida atenção ao lado “cliente” do projeto quando falamos de segurança. Empresas contratam equipes de testes para avaliar se a funcionalidade está sem defeito, se o botão está no lugar certo, mas geralmente não executam testes técnicos (veremos mais a frente) para validar se o projeto está seguro. Existem cuidados simples que podemos tomar para podermos um lado cliente mais seguro. O primeiro cuidado que devemos ter é: “cuidado com regras de negócio no lado do cliente”. Colocar validações de inputs do lado do cliente é normal e é válido, o problema é quando essa validação expõe regras de negócio. Veja a imagem abaixo: O site acima é um serviço público disponível em minha cidade, apenas com os campos alterados para que não seja identificado ( =P ). Vou chamá-lo de UAI_SITE. Note que uma mensagem de erro é exibida no UAI_SITE, mas não foi feita nenhuma chamada Ajax ao servidor. O campo que foi validado é um ID do produto utilizado junto com o ID do usuário para criar um request válido. A validação do código do produto foi feita simplesmente utilizando Javascript e, com isso, um hacker tem acesso à regra de negócio e facilmente conseguiria criar códigos válidos; tendo os códigos válidos em mão um hacker poderia fazer um Brute Force Attack para descobrir um user id válido. Talvez o desenvolvedor não tivesse a maldade de expor a regra de negócio, ou até mesmo teve a boa intenção de poupar uma chamada ao servidor. Existem casos onde é melhor ter uma chamada a mais em um servidor do que expor suas regras de negócio ao mundo. Veremos mais a frente neste post sobre validações do lado do cliente. O segundo cuidado que devemos ter é: “todos os recursos devem ser carregados corretamente”. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro É uma boa prática ter validação de campos do lado do cliente, e em um projeto Web é muito comum utilizar Javascript para realizar essas validações. É sempre bom validar se determinado campo está preenchido, se um formato de data está valido, se algum campo tem o tamanho mínimo necessário, etc. Em alguns momentos podemos utilizar bibliotecas com códigos prontos para facilitar essa rotina tediosa de verificar se um input está preenchido. O problema é quando o código Javascript não é corretamente carregado. Veja a imagem abaixo do que aconteceu ao carregar o UAI_SITE: Todas as validações de dados que utilizassem alguma função do JQuery não funcionariam. Toda vez que um projeto for para produção é necessário validar se não existem erros como de Javascript. O último tópico que veremos é: “cuidado com informação salva no cliente”. Um bom hacker vasculhará todas as páginas que tiver acesso procurando por campos escondidos. Não seja inocente de achar que só por que o campo está escondido nada acontecerá. Caso uma informação sensível necessite ser retornada ao cliente, tenha a certeza de que essa informação está sendo criptografada ou realmente protegida de alguma forma. Tome cuidado quando dados do usuário estão sendo retornado para a tela. Um cuidado simples é não retornar a senha do usuário para a tela. Enviar a senha em texto aberto para deixar um que input HTML ofusque o valor é um erro grave, bastaria o hacker analisar a resposta enviada pelo servidor. Fique atento a URL Cuidado com dados que aparecem na URL. Nunca exponha na URL coisas desnecessárias, como por exemplo, usuário, senha, perfil do usuário ou códigos da regra de negócios. Imagine a URL a seguir: http://site/user/2/profile/2 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Um usuário poderia ficar tentado a trocar a URL acima para: http://site/user/2/profile/3, http://site/user/3/profile/2 e até mesmo para http://site/user/3/profile/3. Se nenhuma validação for feita haverá falha de segurança. Um hacker poderia simplesmente navegar em todos os registros da aplicação. Note que para simular a falha acima não seria necessário ser um hacker, um usuário sem conhecimento técnico poderia alterar a URL e tentar explorar uma falha de segurança. Uma solução para esse problema seria sempre validar se os valores que chegam são válidos. Testes Técnicos É sempre bom ensinar a equipe de testes um modo para tentar burlar as regras de negócio. Mostrar a eles como burlar um JSON ou coisa parecida poderia ajudar a facilitar a detectar prováveis erros de regra de negócio. Ferramentas como JMeter, Postman (plugin do Chrome) ou o Swagger são ferramentas fáceis de usar e que poderiam ser manipuladas por alguém que não entendesse de programação. Bastaria um rápido treinamento de como executar a chamada e como os dados devem ser criados e pronto, a equipe de QA poderia realizar diversos testes que a equipe de desenvolvimento pode ter deixado de fazer. Validações É necessário tratar as informações de nosso projeto como o bem mais valioso. Basta uma informação errada para termos dados corrompidos, relacionamentos quebrados, prejuízo financeiro, etc. Para tratar com o devido respeito os dados do nosso projeto precisamos sempre validar as informações antes de salvá-las. Precisamos ter a certeza de que nossas informações estão com os dados necessários. Mas, onde validar? Validando dados Primeiro lugar que sempre deve haver validação é na camada de negócio. Note que eu disse camada de negócio e não no Controller. Existem desenvolvedores que o único lugar que deixam validações é no Controller e isso é um grande erro. Imagine que uma determinada regra de negócio deva ser utilizada para execução de diversas rotinas, mas a chamada vem de outro Controller. Os dados poderão ser persistidos corrompidos. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Validar se os dados estão validos apenas na camada de negócio nem sempre é uma boa solução, pois pode sobrecarrega-lo. Sempre tenha a validação do lado do cliente seja web, mobile, outro serviço, etc. Entretanto, nunca confie que validação do lado do cliente será suficiente. Validações do lado do cliente podem ser facilmente burladas, e requisições, poderão ser ‘simuladas’ até mesmo de fora do projeto. A vantagem de ter a validação do lado do cliente é: chamadas para verificar se determinado campo está vazio não serão disparadas para o servidor, mas sim resolvidas do próprio cliente. Sempre tenha cuidado ao validar suas informações. Cuidado com arquivos É muito comum ter sites que recebem arquivos enviados por usuários, às vezes, apenas fotos. Será que o arquivo que acabou de chegar, é realmente o que se espera? O que não garante que o arquivo que acabou de chegar não é um executável? Ou algum tipo de arquivo que poderia ser disparado por alguma rotina? Para burlar um upload de um arquivo bastaria trocar o header do request enviado e pronto, alguém poderia enviar um arquivo EXE como se fosse um PNG. Para se proteger desse ataque é necessário que, antes de salvar o arquivo em disco, seja validado qual o tipo do arquivo que acabou de chegar. Uma ótima opção para ajudar nessa validação é utilizar o framework Apache Tika (http://tika.apache.org/). Esse problema pode acontecer caso o nível de permissão utilizado para executar a aplicação seja muito “poderoso”, um usuário root por exemplo (veremos isso mais a frente). Finalizando, tome cuidado com arquivos que acabaram de chegar. Apenas limitar o tipo de arquivo (por exemplo, aceitar apenas *.png) no cliente e determinar o tipo de “Content-Type” para o request não é suficiente. Essas proteções podem ser facilmente burladas. Sempre dê o menor privilégio possível Infelizmente quando diversos projetos são criados nunca é pensado em qual privilégio envolverá o projeto. Ao falar de privilégio no projeto, vamos falar de tudo desde a infra-estrutura até o comportamento da aplicação. Privilégio de usuários: não tem por que um usuário já começar tendo acesso a todas as áreas do projeto e a recursos que ele nunca utilizará. O ideal é programar http://uaihebert.com/protegendo-sua-aplicacao-mini-livro já sabendo ao certo o que o usuário pode ou não fazer/acessar. Uma vez que fique claro o papel de cada usuário dentro do projeto ficará mais fácil o QA (área de testes) realizar o executar os testes, podendo apontar assim falhas de segurança. Sempre deixe o usuário trabalhar apenas com o que ele precisa, ele nem precisa saber que determinado MENU existe no projeto caso não seja ele o responsável por administrar/acessar. Privilégio do servidor: quando nosso servidor é executado ele é executado com o perfil que dispara seu início. Se você faz login com o usuário “jose.de.arimateia”, e ele tem permissão de root, essa aplicação será executada como root. É necessário mesmo que a aplicação rode como root? Imagine um projeto que recebe upload de fotos, mas um hacker envia um arquivo “*.sh”. Caso o projeto execute esse script o código do arquivo “*.sh” terá a permissão de fazer o que quiser, pois ele tem o privilégio de root. Tome cuidado com a permissão dada ao servidor, preferencialmente, ele deve ter o “poder” de alteração apenas dentro de usa pasta e nada mais. É uma má prática utilizar um perfil de root (super user) para executar o projeto. Privilégio do banco de dados: assim como falado do privilégio do servidor, podemos falar com relação ao privilégio do banco de dados. Existe a necessidade de executar com privilégio root? Existem banco de dados que podem executar comandos no sistema operacional, e caso um hacker consiga realizar SQL Injection em seu projeto ele conseguiria fazer o banco de dados afetar o SO. Privilégio do desenvolvedor: todo desenvolvedor precisa de acesso em produção? Todo desenvolvedor precisa ter privilégio de root em área sensíveis da empresa? Em meu primeiro emprego na capital eu apaguei uma pasta de trabalho de uma semana inteira da equipe. Eu precisaria ter esse tipo de acesso? E quantas histórias já são conhecidas de perda de dados em produção por algum erro de desenvolvedor? Outro detalhe importante é: a máquina do desenvolvedor é deve acessar produção? Empresas podem ter prejuízo com desenvolvedor que tem acesso direto a produção, pois sem saber um desenvolvedor pode disparar um teste que afeta produção. Eu creio que um desenvolvedor possa ter acesso em produção para que ele possa analisar dados, procurar problemas, etc; eu também creio que todo desenvolvedor poderia ter apenas acesso de leitura tanto para o log do servidor como para o banco de dados, se necessário. Considerações finais: Sempre tenha mapeado quais diretórios seu projeto precisa acessar. Se seu servidor recebe upload de arquivos, deixe que o servidor tenha permissão apenas do seu diretório e do diretório que receberá os arquivos. Um servidor com permissão exagerada poderia apagar arquivos de outros diretórios, escrever arquivos onde não http://uaihebert.com/protegendo-sua-aplicacao-mini-livro se deve ou até mesmo alterar variáveis de projeto do servidor quando atacado com sucesso por um hacker. Cuidado com senhas fracas. Imagine que seu servidor pode ter sempre alguém tentando acessar. Senhas fracas para o acesso ssh, acesso remoto ou até mesmo pelo próprio projeto poderá servir de porta de entrada para um atacante. Cuidado com usuários muitos comuns. Quantos aqui já não viram um usuário chamado “admin” ou “administrator” em algum projeto? Ou então no sistema operacional? Tenha cuidado com nomes de usuários fracos e simples, isso será mais uma facilidade para um hacker disparar um DoS no projeto. Trate os erros do projeto Tenha a certeza de que nenhuma exceção aparecerá na tela do usuário de modo não amigável. A pior coisa possível seria um stacktrace (mensagem de erro gerado pelo próprio projeto), aparecer diretamente ao usuário final. O tratamento de erro é fundamental por dois motivos: 1. Perda de credibilidade. Um projeto que existe erros não tratados ao usuário perde a credibilidade, e qualquer problema que venha a acontecer o usuário dirá que é culpa do projeto – mesmo que seja erro de negócio. Em que isso afeta o projeto? O usuário pode começar a usar o projeto de modo desleixado e adicionando dados incompletos; um usuário insatisfeito poderia simplesmente pensar: “por que me dar o trabalho de fazer tudo certo se o projeto só mostra erro estranho o tempo todo?”. 2. Prato cheio para hacker. Uma vez que um hacker tenha acesso ao código detalhado de uma mensagem de erro, ele conseguirá trabalhar em cima do projeto simulando erros e até mesmo vendo se na mensagem de erro contém dados importantes. Até mesmo as grandes empresas podem cometer esse tipo de descuido. Veja a imagem abaixo: http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Essa imagem é de um site que pertence a Microsoft. Note que a ip do banco de dados, usuário, senha foram exibidos. Imagine o dano que essa falha poderia causar. Sempre trate os erros da aplicação (esperados ou não). Cuidados com bibliotecas de terceiros É comum em projetos utilizarmos bibliotecas de terceiros, mas até onde levamos em consideração a segurança? Já parou para pensar que nas bibliotecas que utilizamos podem haver Memory Leak (problema de estouro de memória em Java), falhas em consulta de banco de dados (SQL Injection) e outras coisas mais? Sempre fique atento a notícia dos frameworks de seu projeto. Conseguir notícias hoje em dia não é difícil, basta querer. O framework Spring, por exemplo, tem um feed de notícias que pode ser seguido para atualizações. Nem sempre atualizar é necessário, mas em alguns momentos, pode ser crítico. Fique atento aos repositórios utilizados. Existem pessoas que para utilizar determinada biblioteca não pensa duas vezes em adicionar um repositório desconhecido ao projeto. Imagine se o servidor onde esse repositório se encontra é atacado. No lugar do JAR existente um hacker adicionar um JAR ‘batizado’. Uma entrada para ataque hacker poderia ser aberta em seu projeto sem ninguém imaginar. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Versão do Projeto É comum em projetos desktop/mobile encontrar em algum lugar a versão do projeto definida. Para um projeto Web essa informação seria realmente necessária? Vamos tomar, por exemplo, o WordPress que é uma plataforma famosa de blogs. Em sua versão 3.1.3 estava com uma falha de segurança onde um hacker conseguia fazer um SQL Inejction. Rapidamente uma nova versão foi lançada para corrigir esse problema, mas tomando por base que a versão 3.1.3 era conhecida por essa falha de segurança pergunto: “o que impede que um hacker procure blogs que ainda estão na versão 3.1.3 e realize o ataque?”. Tome cuidado ao expor a versão do seu projeto. Um hacker pode estar monitorando as versões do seu projeto, e poderia inclusive, mapear data e horário comum de subidas do seu projeto. Após uma subida de versão é o melhor momento para se descobrir falhas de segurança. Preste atenção com o LOG É comum encontramos projetos que têm um registro detalhado, de tudo que acontece, salvo em um arquivo LOG ou banco de dados; são registrados no arquivo de LOG os dados que vieram na requisição, estágios do processamento de uma requisição e a resposta ao request processado. Tenha cuidado para não registrar dados privados do tipo: senha do usuário ou número do cartão de crédito ou até mesmo o CVV (número secreto que fica atrás do cartão de crédito). Esses dados devem ser evitados de serem salvos em LOG por dois motivos: 1) Um funcionário mal intencionado poderia pegar essas informações e começar a utilizar erroneamente 2) Imagine se um hacker tivesse acesso aos arquivos de LOG… Uma prática que pode ajudar no caso de arquivos de LOG roubados é evitar salvar as entradas de erros como [ERROR] ou coisa do tipo. Se todas as entradas foram salvas apenas como [INFO] isso dificultará um hacker a encontrar os problemas e potenciais pontos de ataque do seu projeto. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Separe seu projeto das camadas Existem diversos projetos que ao irem para produção vão dentro do mesmo artefato (no caso do Java, um arquivo do tipo war ou ear). Uma boa dica seria separar a camada de visualização da camada de negócios em servidores diferentes. Vamos imaginar um projeto onde teremos dois artefatos sendo um para a VIEW e outro para o negócio. A VIEW será responsável para sempre responder os requests dos usuários, mesmo que o servidor de negócios esteja fora do ar. O servidor de negócios será responsável pelas regras de negócio e o acesso ao banco de dados. As vantagens de separar a camada de negócios da camada de visualização são: 1) Em caso de ataque seria possível bloquear já a parte de negócio modo mais rápido, sem ter que parar o acesso do usuário ao projeto. Uma mensagem de erro mais amigável seria exibida ao invés de um 404 ou qualquer outro erro de indisponibilidade. Um hacker poderia conseguir acesso a maquina do projeto de view, mas ainda não teria o devido acesso a maquina das regras de negócios. 2) É possível fazer deploy separadamente. Caso uma correção fosse feita no código de regras de negócio a view não precisaria parar para que o deploy de negócio fosse feito. 3) Ter máquinas separadas possibilita focar os melhores recursos de Hardware para a parte que está tendo mais trabalho. Existem várias técnicas possíveis para realizar a comunicação entre view e negócio quando se encontram em camadas diferentes: RMI, SOAP, RESTFul (com XSTL ou sem). Para aqueles que já trabalham com o serviço separado da VIEW é necessário ter o cuidado de não expor a máquina do serviço diretamente para web, deixar que apenas a máquina da view fique em contato direto com a máquina de serviço. Se necessário disparar algum serviço da máquina da serviço, seja uma rotina ou até mesmo alguma consulta manual, pode-se criar acessos via SSH ou por VPN. Evite que seu servidor de serviços tenha porta direta com a web, o ideal é que a camada de view seja utilizada como Proxy. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Comentários nem sempre são saudáveis É possível encontrar desenvolvedores que comentam tudo em seu código, e, se possível, comentariam o próprio comentário. De acordo com o livro Clean Code o código deve ser claro e fácil de ser lido, de modo que nem o comentário seria necessário para explicar o que acontece dentro do método. Não vou entrar em detalhes sobre boas práticas de programação, mas vou falar apenas que:comentários podem ser nocivos ao projeto. Existem comentários que podem levar a erros de programação ou levar informação do projeto para um hacker. O primeiro momento que um comentário poderia ser nocivo é quando o comentário está desatualizado. Imagine que o seguinte comentário é encontrado em um código: /* Método que processará e salvará o registro no DB */. Imagine que um desenvolvedor faz uma refatoração desse método para que seja apenas realizado o processamento, mas no comentário não foi removido o texto que fala sobre salvar o registro no DB. Quem ler o comentário vai acabar pensando que o método faz duas coisas quando na verdade faz apenas uma. Outro problema de documentação em excesso é quando comentários são expostos no código detalhando a regra de negócio. O problema dessa abordagem é que na hora de empacotar o código e enviar para produção um hacker poderia vasculhar o código procurando por um comentário que possa esclarecer algo. Quando o código de uma classe java é compilado seus comentários são retirados, mas e quanto aos comentários que estão presentes no HTML e arquivos XML? É preciso ter cuidado com os comentários que aparecerão nos arquivos, e principalmente nos arquivos HTML pois qualquer um terá acesso ao que está escrito. Sempre valide seu código Sempre utilize ferramentas que possam validar seu código. Existem ferramentas grátis que fazem toda a validação do código para aumentar o nível de qualidade do projeto. Cito as seguintes ferramentas abaixo (conhecidas como analisadores de código estático): FindBugs http://uaihebert.com/protegendo-sua-aplicacao-mini-livro PMD CheckStyle ESC/Java As ferramentas citadas acima são gratuitas e servem para fazer análises e mostrar pontos que poderiam gerar problema no código. Essas ferramentas são customizáveis podendo eliminar regras que não fazem sentido ao projeto. Existem plugins que podem adicionar essas ferramentas analisadoras a sua IDE. É possível também utilizar ferramentas de testes automatizados para validarem as regras de negócio e rodar os analisadores de código estático. É possível configurar frameworks como Sonar e Jenkins para realizar testes automatizados e também executar os analisadores de códigos estáticos. A configuração das ferramentas citadas acima pode dar trabalho, mas ao final do processo seu projeto estará mais protegido contra falhas de implementação. Tenha um CheckList É importante sempre ter uma lista de validações necessárias. Ao falar de CheckList podemos levantar os seguintes itens: Veja se todos os recursos foram carregados com sucesso – arquivos Javascript, módulos da aplicação, integrações do projeto Valide se as regras de negócio estão ativas: o Regras que já foram quebradas devem ter uma maior atenção Quais configurações básicas de cada servidor? o Ao subir um servidor novo tenha certeza de ter uma lista de configurações necessárias. Validar variáveis de ambiente, configurações para “load balance” e demais ajustes podem ficar em uma lista de verificação. A rotina de pós deploy, além de um CheckList, poderia ter um caderno de testes para validação de regras de segurança, e a certeza de que nenhum bug foi adicionado. Só por que todos os testes não apresentaram erros em DEV ou HOMOLOG não significa que erros não aparecerão em produção. Cuidado com a equipe de TI É importante sempre pensar que a equipe de TI pode se tornar uma porta de entrada para ataque hacker. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Exposição dos dados Pode acontecer que um funcionário, sem querer, exponha informações sensíveis da empresa. Veja a triste história abaixo: http://uaihebert.com/protegendo-sua-aplicacao-mini-livro É possível ver na imagem acima uma pessoa que acabou por expor usuário/senha e teve todo o banco de dados apagado. Imagine se a pessoa copiou o banco de dados antes de apagar? Qual seria o tamanho do dano? Infelizmente não é possível monitorar todas as atividades de todos os funcionários, mas é possível orientar a equipe sobre o que poderia e o que não poderia ser postado em fóruns. Eu não creio, e abomino a idéia, de que bloquear a utilização de fóruns seja a solução para esse problema. O ideal seria enviar um informativo à equipe deixando claro para evitar colocar usuário/senha/caminho de banco de dados, etc. Cuidado com o código escrito É bom reforçar através de bate papos que o que está sendo escrito não é apenas um pedaço de código qualquer, mas sim algo importante que pode impactar todo o projeto. A cada dia que passa um desenvolvedor pode ficar mais insensível com o código que escreve e alguns detalhes começarem a escapar, bugs aparecer, etc. Sempre reforce a necessidade de um código de boa qualidade. Futuro ex-funcionário Esse é um tipo de funcionário que merece toda a atenção. Indiferentemente se a pessoa se demitiu ou foi demitida pela administração é preciso ter cuidado. Infelizmente já ouvi diversos relatos de ex-funcionários que deixaram códigos maliciosos no projeto, ou até mesmo porta de entrada nos servidores da empresa. Infelizmente em caso de demissão é preciso que essa pessoa tenha seus acessos restritos imediatamente, e seus passos rastreados. Tome conta do seu projeto, afinal, o funcionário sairá e provavelmente você será responsável pelo legado dele. Code Review / Pair Programming Infelizmente Code Review e Pair Programming são práticas não muito adotadas, mas que ajudam na proteção e evolução do projeto. Code Review e Pair Programming são técnicas de metodologias ágeis onde mais de um desenvolvedor fica responsável pelo código salvo no repositório (procure na internet por mais detalhes, pois ambas as técnicas têm comportamentos diferentes). http://uaihebert.com/protegendo-sua-aplicacao-mini-livro A vantagem de realizar o Code Review e/ou Pair Programming é que conhecimentos são transmitidos e a questão de segurança passada de uma pessoa mais experiente em determinado assunto para outra pessoa mais novata. Essa é uma prática excelente para investir. Fique atento a terminologia Tenha cuidado para que uma regra de negócio ou funcionalidade não tenha mais de um termo, isso pode causar confusão. Imagine que a funcionalidade de desativar um usuário será entregue na próxima versão do projeto, mas desenvolvedores começam falar em: desativar usuário, apagar usuário, alterar perfil do usuário, etc. Diversos termos para a mesma funcionalidade/regra pode levar a erros de implementações no futuro, pessoas podem achar que estão falando da mesma coisa quando na verdade não estão. Pode ser que um desenvolvedor esteja falando sobre apagar um usuário quando o outro acha que o assunto é apenas desativar um usuário. Proteja a senha do modo correto Nunca salve senha de usuário em banco de dados sem estar criptografada. Uma senha não protegida por uma criptografia é um dos piores erros que uma aplicação pode ter. Existem pessoas que criptografam senha um uma lógica criada por ele mesmo, e isso é uma péssima prática. O ideal é utilizar algoritmos seguros que já existem no mercado para realizar a criptogafia. Existem algoritmos de criptografia que já foram validadas matematicamente por diversas pessoas como sendo segura; uma função de criptografia caseira poderia ser facilmente quebrada. Ao usar uma função de criptografia já existente no mercado é possível ter a certeza de que o código é seguro, e caso alguém quebre, a notícia correrá e será possível tomar medidas de proteção. É preciso ter cuidado com algoritmos de criptografia fracos que já foram quebrados. Veja a listagem abaixo dos algorítimos que já são considerados como desatualizados: MD4 http://uaihebert.com/protegendo-sua-aplicacao-mini-livro MD5 SHA Chaves simétricas com um tamanho menor que 128-bits ARC e RC4 (ou qualquer tipo de cipher stream) Block ciphers usado no modo Electronic Code Book (ECB) Uma boa função de criptografia seria a SHA-256 que ainda não foi quebrada e é recomendada. Tome muito cuidado com MD5 que é comumente utilizada em tutoriais encontrados na internet. Boas práticas para controle de acesso Existem projetos onde algumas ações ou áreas que não devem estar acessíveis a todos os usuários. Para determinar se usuários podem ou não acessar determinado recurso é utilizado o conceito de perfil do usuário. Por exemplo: um usuário com perfil ADMINISTRADOR poderia executar qualquer função do projeto; um usuário com perfil GERENTE poderia apenas controlar ações de seus funcionários. Alguns desenvolvedores pensam que basta esconder o botão que nenhum problema acontecerá, outros desenvolvedores resolvem bloquear tudo e só liberar o que o usuário precisar. Abaixo veremos técnicas que ajudarão a determinar acessos de segurança por perfil de usuário. Esconda o botão/link, mas proteja o código Imagine que apenas o usuário do perfil GERENTE poderia editar as horas extras de um funcionário. Para evitar que um funcionário edite suas próprias horas extras o desenvolvedor poderia esconder o botão. Bastaria utilizar um código javascript, classe css, scriplet ou qualquer coisa utilizando o valor do objeto do usuário: user.isManager(). O valor recuperado seria utilizado de algum modo pela página para definir se o link seria ou não escondido. O problema acontece quando um funcionário ganancioso, que quer ter mais horas extras sem trabalhar, ao passar atrás do monitor do gerente viu a seguinte URL:http://project/user/33/workedHours. O que aconteceria se uma pessoa com o perfil USUARIO tentasse acessar o projeto digitando a URL diretamente no browser? Nunca proteja seu projeto apenas escondendo um recurso, sempre valide cada regra ao ser acessada. É necessário que, para cada request de acesso as horas extras de um funcionário, uma validação de segurança fosse executada no servidor. Nunca confie que ao esconder algo da tela do usuário a proteção estará completa. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Conheça a necessidade do seu usuário Ao invés de bloquear tudo e depois ir liberando aos poucos seria melhor saber o que o usuário precisa. A vantagem de investir um pouco de tempo para entender o que o usuário precisa é justamente amenizar a experiência do usuário. Um usuário que tem a necessidade de sempre solicitar acesso a determinado recurso no projeto, pode acabar não gostando do projeto e tratá-lo de qualquer modo. Existe também o problema de um usuário com muita permissão desnecessária que poderia esquecer seu computador desbloqueado e qualquer pessoa poderia navegar no projeto. Uma boa solução para esse problema seria estudar quais acessos determinada pessoa ou papel dentro da empresa necessita ter, e criar o conceito de grupos ou papeis dentro do projeto específicos. Grupos dentro do projeto teriam permissões pré-determinadas e a chance de acertar o que casa usuário necessita aumentaria. Sempre oculte Não existe motivo para exibir algo que o usuário não possa acessar. Aplicações desktop costumam deixar um menu desabilitado visível. O problema de deixar um menu visível e bloqueado é que um usuário pode começar fazer de tudo para habilitar aquele menu. Existem casos que o fluxo da tela é claro quando determinado botão ficará habilitado. No caso de um formulário onde o botão Salvar fica desabilitado enquanto os campos não forem corretamente preenchidos, seria perfeitamente normal utilizar essa abordagem. Imagine agora uma aplicação corporativa onde está sendo exibido o seguinte menu de modo desabilitado: “editar horas extras de todos funcionários”. Qual a necessidade de exibir essa função desabilitada para usuários sem permissão se apenas um gerente teria acesso a ela? Se um usuário nunca poderá habilitar determinada opção, qual é a necessidade de deixar a opção visível? Uma opção desabilitada pode levar usuários comuns a tentarem habilitar dessa opção, e mostrar a hackers opções que ele nem precisava saber que existiria. Se possível, sempre oculte o que o usuário não deve ver. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Políticas de Segurança Toda projeto necessita de uma política de segurança, alguns exemplos seriam: tamanho de senha, quem poderia criar usuários, quantas pessoas devem aprovar determinada ação até que seja executada. O problema começa quando a política de segurança está muito restrita é incômoda. Ter acesso somente por digital seria uma política restrita que não seria incômoda, basta o usuário colocar o dedo em um sensor que o problema está resolvido. Um dos maiores problemas que vamos falar aqui é a questão de políticas de segurança aplicadas a senhas. Uma política de senha muito restrita é um exemplo clássico de problemas com falha de segurança. O maior problema de segurança nesse caso viria do próprio usuário do projeto. Imagine um projeto onde uma senha válida tem que ter no mínimo uma letra caps alto, ter um número, ter um símbolo como !@#$%*, tem que ser trocada de 3 em 3 meses e não pode ser nenhuma das 5 senhas últimas utilizadas. O problema dessa abordagem é que o usuário começa a sabotar as senhas, será muito fácil que suas senhas comecem a ser algo como: SENHa1!, SENHa2!, SENHa3!. Um hacker que descobre uma senha muito usada por um usuário (até mesmo de um site de notícias), poderia começar a testar valores sequenciais para invadir o projeto. Outro problema de senha muito restrita é “post it”. Usuários que têm dificuldade com computadores, mas precisam utilizar o projeto, podem justamente colocar a senha em um post it no monitor. Bastaria uma pessoa mal intencionada passar pelo lugar onde se encontra o post it, ver essa senha, e começar fazer o que quiser com o usuário da pessoa. É importante ter em mente que é necessário ter algum tipo de política de segurança no projeto. Uma boa prática seria não ter muias regras restritivas, mas impedir que a senha fosse algo como: data de aniversário, data de casamento, nome do cônjuge ou qualquer outra variável que possa ser descoberta facilmente por alguém que não seja da empresa. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Evitando falhas de códigos e/ou frameworks Não exponha tecnologias desnecessariamente Nunca misture os tipos Veja o código abaixo: 1 char charValue = 'A'; 2 int i = 1; 3 4 boolean result = // methodh that returns true 5 System.out.print(result ? charValue : 1); 6 System.out.print(result ? charValue : i); O que poderia dar errado no código acima? O primeiro valor a ser impresso seria A, mas o segundo 65! Note que na primeira condição foi utilizado o número 1 diretamente e com isso o Java comparou esse número com um CHAR. O problema da segunda opção é que o Java jogou o tipo de CHAR para int e o problema ocorreu. A solução para esse problema é justamente não misturar os tipos na hora de uma comparação. Esse tipo de problema poderia levar a bugs extremamente difíceis de detectar. Toda vez que for necessário comparar valores utilize o mesmo tipo. Utilize chaves nos “IFs” É muito fácil e simples fazer um IF como abaixo: 1 2 if(tax == 43) executeMethod(); O problema do código acima é que uma pessoa novata em Java e no projeto poderia tentar fazer algo como: 1 if(tax == 43) 2 executeMethod(); 3 runOtherMethod(); É algo simples, mas que poderia facilmente acontecer em um projeto onde se tem pessoas novatas na linguagem programando. Adicionar chaves ao começo e final de um método não vai deixar o código ilegível, mas pelo contrário, deixará o código mais fácil de ler: http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 1 if(tax == 43){ 2 executeMethod(); 3 } 4 runOtherMethod(); Mesmo uma pessoa novata, ao ver o código acima, entenderia que para executar o método caso o if retornasse true, bastaria colocar a chamada ao outro método dentro do if. Inteiros com Flutuantes Evite realizar operações matemáticas entre tipos de números diferentes. Haverá perda de precisão ao misturar Double com Integer, por exemplo. Sempre converta Integer/Long para Float/Double quando for realizar uma operação que misture os dois. Sempre programe defensivamente Veja o código abaixo: 1 boolean okToAccess = true; 2 3 try { 4 openTheFile(); 5 } 6 catch (SecurityException x) { 7 // access denied 8 <code>okToAccess</code> = false; 9 10 11 } catch (...) { // other exception } 12 Qual o problema do código acima? Caso algum erro aconteça que não seja do tipo SecurityException um usuário conseguirá acesso ao recurso, pode ser que ele não deveria ter acesso, mas alguma outra exceção aconteceu e com isso um acesso indevido acontecerá. Uma boa solução seria: http://uaihebert.com/protegendo-sua-aplicacao-mini-livro 1 boolean okToAccess = false; 2 3 try { 4 openTheFile(); 5 accessGranted = true; 6 } 7 catch (SecurityException x) { // access denied 8 9 10 11 } catch (...) { // other exception } 12 Veja que primeiro o acesso é negado e, somente após todas as validações de segurança, é que o acesso ao recurso estaria liberado. Isso também poderia ser considerado boa prática para diversos outros aspectos como: um método onde precisamos saber se determinado usuário deve ou não ler determinado dado já pode começar com permissão negada e, após as validações de segurança, o usuário teria o acesso liberado. http://uaihebert.com/protegendo-sua-aplicacao-mini-livro Por hoje é só Como eu disse no começo, não sou nenhum especialista no assunto, apenas estou compartilhando coisas que aprendi durante leitura ou vivenciei no dia a dia do desenvolvimento. Espero que o post tenha ajudado a esclarecer dúvidas e guiá-los para uma solução mais próxima do seu problema. Abaixo as referências do material que utilizei: http://msdn.microsoft.com/en-us/security/aa570401.aspx http://www.sans.org/reading-room/whitepapers/securecode/secure-software-developmentcode-analysis-tools-389 http://www.safecode.org/publications/SAFECode_Dev_Practices1108.pdf https://blogs.akamai.com/2013/09/slow-dos-on-the-rise.html http://en.wikipedia.org/wiki/Brute-force_attack Java Coding Guidelines: 75 Recommendations for Reliable and Secure Programs Qualquer dúvida basta postar, até mais. Até a próxima! \o_