Imagem por Kyle Glenn

Identificando vulnerabilidades client-side em seu projeto web

Neste artigo falaremos sobre vulnerabilidades comuns em projetos web, pontos de atenção e alguns meios de prevenção.

O intuito é apresentar as vulnerabilidades e servir como ponto de partida caso queira se aprofundar em um tópico específico.

Fique a vontade para abordar os assuntos na ordem que lhe for mais conveniente.

Motivação

Ataques podem ocorrer por mera curiosidade, com boas ou más intenções. Cada ataque possui um fluxo específico, mas sempre com base nos seguintes estágios:

  • Coletar informações sobre sua aplicação
  • Procurar por vulnerabilidades
  • Estabelecer um ponto de controle
  • Utilizar esse ponto de controle como base para ataques mais severos

Tipos de ataques

Vamos dar uma olhada em alguns dos ataques mais conhecidos. Os ataques listados são descritos do ponto de vista client-side.

Cross-site Scripting (XSS)

Cross-site Scripting é um ataque de injeção que tem como objetivo colocar conteúdo em um local que é designado para texto, enganando o navegador para que execute tal conteúdo como código.

Esse tipo de ataque pode ser separado por categorias, sendo elas:

Persistent XSS

Esse tipo de ataque ocorre quando conteúdo malicioso é armazenado no seu banco de dados — cadastrando uma informação contendo uma tag script, por exemplo

Ao recuperar essa informação para renderizar uma página, o navegador pode interpretar essa tag como código ao invés de texto, executando um trecho de código potencialmente malicioso no contexto de sua aplicação.

Uma abordagem comum para se prevenir contra esse tipo de ataque é realizar o escaping das tags, transformando-as em texto antes de armazenar a informação.

Reflected XSS

Ao realizar uma pesquisa em um site, é comum ter termo pesquisado refletido pelo servidor para o usuário em forma de mensagem, como “Não encontramos resultados para (termo pesquisado)”.

Essa abordagem cria possibilidades para Reflected XSS, um tipo de ataque que ocorre quando uma resposta ou estado temporário da aplicação é utilizado como meio para executar um trecho de código.

Ao refletir o termo de volta para o usuário, o browser pode ser enganado a executar seu conteúdo como código, caso contenha uma tag script.

DOM Based XSS

Esse tipo de ataque ocorre exclusivamente no front-end — ao renderizar os parâmetros de uma URL diretamente na página sem realizar o escaping.

Blind XSS

Esse tipo de ataque explora vulnerabilidades em outras aplicações nas quais o usuário não possui acesso sob circunstâncias corriqueiras, como projetos internos.

Imagine uma aplicação responsável por ler os logs de atividade de suas aplicações. Sua aplicação pública pode ser enganada a realizar o log de um determinado trecho de código que, quando executado pela aplicação interna, causará certos efeitos colaterais.

Esse tipo de operação é perigosa pelo fato de que o ataque pode ser realizado anos depois do log ter sido registrado, e, por estar em uma aplicação interna (que tende a não ser tão rigorosa em questões de segurança), terá certos privilégios como ler todos os dados que a aplicação tem acesso.

Pontos de vulnerabilidade

Sempre que sua aplicação consome dados públicos existe a possibilidade de um ataque de XSS. Evite utilizar informações fornecidas pelo usuário diretamente em tags, atributos, blocos como style, script ou comentários.

Outros pontos de atenção são:

  • Conteúdo embutido (Iframes, embeds)
  • Editores de texto (WYSIWYG)
  • Áreas onde a URL pode ser customizada
  • Áreas onde o conteúdo informado é refletido para o usuário (notificações, validações, etc)
  • Áreas onde os parâmetros da URL são renderizados na página

As consequências desse tipo de ataque podem variar desde roubo de informações à perda de controle total da aplicação, dependendo do usuário que for comprometido.

Possíveis soluções

Content Security Policy (CSP)

Content Security Policy (CSP) é uma camada de segurança responsável por auxiliar na prevenção de ataques como XSS e packet sniffing.

Navegadores não conseguem diferenciar entre um script fornecido pela origem da aplicação e um script externo, carregado através de uma CDN, por exemplo.

Para garantir que certos tipos de conteúdo serão carregados de fontes confiáveis, podemos utilizar uma tag meta ou de um cabeçalho de resposta, indicando quais domínios devem ser considerados seguros.

O conteúdo da tag ou cabeçalho utiliza o seguinte formato base:

Content-Security-Policy: política fonte-1; fonte-2;
ou
Content-Security-Policy: política-1 fonte-1; fonte-2;
política-2 fonte-1;
  • Política de segurança (Diretivas)

Define o tipo de conteúdo a ser controlado. Algumas políticas de segurança comumente utilizadas são:

script-src — Fontes externas de scripts
style-src — Fontes externas de CSS
font-src — Fontes externas de fontes
child-src — Contextos internos de execução (frames, workers)
connect-src — Pontos de conexão (fetch, websockets)
form-action — Fontes para onde formulários podem ser submetidos
img-src, media-src e object-src — Fontes de mídia
upgrade-insecure-requests — atualizar links da página de HTTP para HTTPS
default-src — Fallback para diretivas não definidas

  • Fontes

A lista de fontes é composta das URLs das origens consideradas seguras, separadas por ponto e vírgula.

Além das URLs, podem ser utilizadas quatro palavras-chave:

none — Bloqueia todas as fontes listadas
self — Permite o domínio atual (exceto subdomínios)
unsafe-inline — Permite Javascript e CSS inline
unsafe-eval — Permite a utilização do método eval()

Tais palavras-chave — quando utilizadas — devem ser envolvidas por aspas.

Exemplo de utilização da tag e cabeçalho de Content-Security-Policy

Caso a tag ou o cabeçalho não sejam informados, todos os domínios serão permitidos.

Samy is my hero, o famoso worm do Myspace, foi espalhado utilizando XSS.

Caso queira saber mais sobre o worm, leia o artigo do próprio Samy, ou dê uma olhada em sua implementação.


Cross-Site Request Forgery (CSRF)

Ataques de Cross-Site Request Forgery tem como objetivo realizar ações não autorizadas através de um usuário autenticado.

Esse tipo de ataque é comum em aplicações que utilizam autenticação básica, tirando vantagem do fato de que as credenciais do usuário são trafegadas através de cookies enviados nas requisições.

Pontos de vulnerabilidade

  • Servidor espera um cookie ou credencial nas requisições para autorizar uma ação

Possíveis soluções

REST APIs

APIs REST são imunes à ataques de CSRF devido ao fato de não preservar estado entre requisições — sem depender de dados armazenados em cookies.

Mesmo se um cookie for enviado com a requisição, as informações contidas no mesmo serão simplesmente ignoradas.

CSRF Tokens

CSRF Tokens são valores únicos enviados a cada requisição.

Sua função é servir como prova de que o usuário que realizou a requisição está autenticado, e que a requisição originou de uma fonte confiável.

Tokens não devem ser reutilizados — um novo valor deve ser gerado para cada requisição.

No lado do servidor podemos encontrar uma lista de tokens considerados válidos. Para ser considerado válido, cada token deve satisfazer uma determinada condição, como ser divisível por 14265 e 2860, por exemplo.

Request Origin

Uma maneira de se prevenir contra ataques de CSRF é validar a origem das requisições.

Navegadores atuais enviam a cada requisição um cabeçalho indicando sua origem, que não pode ser alterado utilizando código client-side.

Esse cabeçalho pode conter os seguintes nomes:

  • Origin
  • Referer
  • Host ou X-Forwarded-Host (caso esteja utilizando algum proxy)

Cross-Origin Resource Sharing (CORS)

CORS é o mecanismo que permite que navegadores enviem requisições entre domínios diferentes.

Antes de cada requisição, uma requisição do tipo OPTIONS é realizada — o preflight. Essa requisição não pode ser controlada e tem como propósito indicar para o servidor o tipo de requisição está para ser realizada e quais cabeçalhos serão enviados.

Por sua vez, o servidor retorna o cabeçalho Access-Control-Allow-Origin, indicando se aquele tipo de requisição é permitida, juntamente com todos os outros tipos de requisições permitidas para aquele domínio.

Após receber autorização do servidor, a requisição deixa de ser enviada por um determinado período de tempo — incluso na primeira resposta de autorização.


Clickjacking

Também conhecido como UI Redress Attack, Clickjacking tem como objetivo redirecionar o clique do usuário para realizar uma ação diferente da desejada.

Esse feito é realizado utilizando iframes e camadas transparentes responsáveis por capturar os cliques do usuário.

Por exemplo, um site é carregado em um iframe escondido na página que o usuário está interagindo. Um container transparente é colocado sobre todos os elementos da página.

Ao tentar clicar em um botão, o evento é capturado pelo container e redirecionado para dentro do iframe, disparando uma ação indesejada por parte do usuário.

Esse mecanismo também pode ser utilizado para capturar eventos de teclado — posicionando um campo de texto falso exatamente sobre o original. Isso cria a ilusão de que o usuário está digitando no próprio site.

Quanto mais elaborado o ataque, menores são as chances do usuário perceber que não está interagindo com o conteúdo esperado.

Possíveis soluções

X-Frame-Options

X-Frame-Options é um cabeçalho HTTP responsável por indicar se é permitido renderizar uma página em um iframe.

X-Frame-Options: deny
X-Frame-Options: sameorigin
X-Frame-Options: allow-from https://example.com/

Os navegadores Chrome e Firefox não aceitam allow-from, sendo necessário recorrer a diretiva de CSP frame-ancestors.

Content-Security-Policy: frame-ancestors 'none';
Content-Security-Policy: frame-ancestors http://*.example.com;

Third Party Assets

Uma possível vulnerabilidade é consumir dependências de fontes externas, como:

Content Delivery Networks (CDNs)

Content Delivery Networks são redes para distribuição de conteúdo espalhadas em varias regiões.

Seu objetivo é permitir o consumo de conteúdo necessário de um ponto geograficamente próximo à sua localização atual, melhorando sua performance.

Exemplo de consumo de recursos de uma CDN— jQuery

CDNs podem ser consideradas pontos de vulnerabilidade por ser necessário confiar que o conteúdo disponibilizado nunca será alterado.

Gerenciadores de dependência

Package managers como NPM e Yarn dispõem de um sistema chamado versionamento semântico, o que nos permite definir quais versões das dependências queremos utilizar.

Dependendo da maneira como os pacotes são versionados, patches e minor releases podem ser incorporadas a sua aplicação, resultando em comportamentos inesperados.

Exemplo de versionamento que permite a atualização de minor releases

Bibliotecas importadas dinamicamente

Algumas bibliotecas são disponibilizadas através de uma tag script que, ao ser interpretada pelo navegador, cria e insere na página uma nova tag script, responsável por buscar o código da biblioteca dinamicamente.

Exemplo de importação dinâmica de uma biblioteca externa— Google Analytics

Essa abordagem é considerada vulnerável pelo fato de que o código da biblioteca pode ser atualizado sem a necessidade de realizar um novo deploy da aplicação que a consome.

Possíveis soluções

Subresource Integrity

Para garantir que o conteúdo de uma CDN sendo utilizado não foi alterado, podemos utilizar nas tags link e script o atributo integrity.

Nesse atributo é informado um hash representando o conteúdo do arquivo, criptografado em base64.

Se o conteúdo do arquivo for alterado na CDN — e o navegador tiver suporte a SRI — o mesmo irá se recusar a buscar o conteúdo novo.

Exemplo de utilização do atributo integrity — Bootstrap

O atributo crossorigin informa o navegador para não enviar cookies na requisição, aumentando a segurança.

Version locks

Version locks são arquivos gerados pelo gerenciador de dependências ao realizar o build das bibliotecas, indicando qual versão deve ser utilizada para aquele build.

Caso utilize NPM, esse arquivo chama-se package-lock.json.

Para o Yarn, chama-se yarn.lock.


Conclusão

O momento crítico de um ataque não é necessariamente a última etapa do processo. Ataques ocorrem em incrementos, então o ponto de controle obtido através de um ataque será utilizado como ponto de partida para ataques mais severos.

Um simples ataque de XSS pode parecer insignificante, porém eventualmente ele pode conseguir as credenciais de um usuário administrador, permitindo colocar um arquivo em um local específico que será utilizado para instalar um rootkit, e assim por diante até conseguir total controle da aplicação.

Casos interessantes

That’s all folks! Espero que tenham gostado!

Fique à vontade para entrar em contato comigo no twitter — @gcolombo_.

Obrigado!


Gostou do artigo? Compartilhe sua opinião conosco!

Não esqueça de seguir nossa página para receber todas as novidades :)