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_
Download

Sumário - uaiHebert