Rafael Fidelis

I write about programming and random things

Exploitando E Tomando Controle Total De Uma Aplicação Node.js + MongoDB

| Comments

NodeJS + MongoDB Créditos da imagem: Microsiv

Introdução

Eta nóis! As falhas de seguranças em aplicações web brasileiras não param de aparecer, no ultimo post eu contei um pouco sobre uma falha de segurança em um uma fintech que permitia o roubo de contratos bancários dos usuários da plataforma. A minha impressão é que a maioria das startups brasileiras não tem nenhuma maturidade para proteger os dados dos seus usuários e também das empresas que utilizam os seus serviços.

O que mais me impressiona é que a maioria dessas falhas são TÃO básicas que chegam a me dar vontade de chorar, como é possível que empresas que receberam milhões em investimento sejam tão amadoras quando se fala da proteção dos dados e informações dos seus usuários?

Nesse post eu vou mostrar como tomei controle total da área administrativa de QUALQUER cliente dessa aplicação - sendo assim possível obter informações privilegiadas e sigilosas de grandes empresas brasileiras e internacionais - e também como um endpoint permitia que qualquer pessoa baixasse TODOS os usuários(cerca de 115 mil) do site em menos de 1 minuto.

Eu separei esse post em 2 partes: Na primeira parte não tem nada de técnico: eu busco explicar o quão danosa essas falhas podem ser e discuto um pouco o porque das empresas brasileiras serem tão negligentes com os nossos dados.
Em seguida discuto os detalhes técnicos para que outros desenvolvedores/CTOs/CEOs/qualquer pessoa interessada possam ter noção de como um ataque desse é simples na prática, e como isso poderia ser evitado.

OBS: As escolhas de banco de dados e linguagem de aplicações não querem dizer absolutamente nada do ponto de vista de segurança, a treta aqui não está no Node(JS) e também não está no MongoDB(NoSQL), o erro é humano e de arquitetura de software.
OBS 2: Então beleza, segura esse hate ai de JS e/ou Mongo - quem nunca??? - e simbora nessa?!



Falhas básicas, consequências dramáticas

Nesse blog eu tento escrever sobre os possíveis impactos que uma falha de segurança dessas pode ter para os donos desses dados, ou seja: o cidadão comum.
Como já analisado em outros posts, a maioria das falhas de segurança são extremamente básicas, que inclusive são as listadas no Top 10 da OWASP.

Ataques de Pishing e Roubo de Identidade

Vou quebrar um pouco o fluxo do post e falar um pouco sobre os riscos envolvendo os vazamentos desses dados. Abaixo linkei vários posts que falam um pouquinho melhor sobre tudo isso, não deixe de ler! (Se você quiser pular essa parte e ir direto pra parte técnica, sinta-se a vonts)

Primeiro, vamos a definição do Avast para Pishing:

Phishing é uma maneira desonesta que cibercriminosos usam para enganar você a revelar informações pessoais, como senhas ou cartão de crédito, CPF e número de contas bancárias. Eles fazem isso enviando e-mails falsos ou direcionando você a websites falsos.

Certamente você já recebeu emails e/ou SMS e até mesmo telefonemas falsos que informavam que você precisava atualizar seus dados em um determinado site, se você é brasileiro: eu tenho quase certeza disso!

Dai você fica se perguntando: Como esses filhos da puta conseguiram meus dados?(numero de telefone, numero de cartão de crédito, email, nome dos pais, data de nascimento, numero de agencia bancaria, e demais informações privadas).

Essa pergunta é REALMENTE difícil de ter resposta no Brasil, já que VÁRIAS EMPRESAS E O PRÓPRIO GOVERNO tem politicas bem bostas de seguranças em relação os dados e a privacidade das pessoas, quer exemplos? Aqui vai:

Além das empresas que não contribuem para melhorar esse cenário de segurança no Braza temos alguns bandidinhos mequetefres - e outros nem tantos (Exemplo) - responsáveis por aplicar golpes utilizando esses dados, vale citar que as estatísticas nos lembra que a CADA 20 SEGUNDOS um brasileiro é vitima de fraude de identidade, ninguém tá a salvo!!

Nós temos que nos revoltar com essas empresas! O usuário também tem que mudar o seu mindset e entender que essas empresas não são mais do que prestadoras de serviço e não estão fazendo nenhum favor pra ninguém, por isso temos o total direito de processá-los judicialmente e cobrar para que ofereçam um serviço mais seguro! No Brasil a questão da segurança é muito negligenciada nós como cidadãos brasileiros temos que nos revoltar e começar a sabotar essas empresas.

Você deve ter visto que recentemente a gigantesca empresa de analíse de crédito Equifax(que seria equivalente ao Serase Experian no Brasil) que presta serviços para o governo dos EUA e para as empresas daquele país vazou dados de 143 milhões de pessoas(levando em consideração que os EUA tem cerca de 300 milhões e excluindo crianças, isso representa praticamente METADE de toda a população). Com citação da matéria do G1:

O caso já é considerado um dos vazamentos mais graves da história, não só por causa da quantidade de registros envolvidos - que é bem menor que o de casos anteriores, como o do Yahoo -, mas porque empresas como a Equifax detêm informações bastante pessoais de consumidores em seus bancos de dados.

O próprio ex-CEO Richard Smith(que parece ter sido demitido e um BR BR assumiu) da empresa disse:

Esse é o momento mais humilhante em nossos 118 anos de história.

Essa empresa está recebendo inúmeros processos - alguns na casa de 5 BILHÕES - por parte da população, das empresas, e também do governo(ex: A cidade de São Francisco), agora eu me pergunto: será que isso seria ignorado no Brasil?

Esse mesmo cara Richard Smith testemunhou diante de um painel na Câmara dos Deputados dos EUA no dia 3 de outubro, depois de cerca de 40 Estados se juntaram a uma investigação sobre como a empresa lidou com o vazamento desses dados. É isso que temos que começar a fazer no Brasil, começar a processar essas empresas todas e levar elas até os tribunais para responderam por essas irresponsabilidades!

Veja abaixo um pedaço do julgamento aonde a senadora Elizabeth Warren praticamente destroi o CEO do Equifax, será que um dia veremos algo parecido no Brasil?

OBS: Parece que a falha explorada no caso da Equifax foi no framework Open Source desenvolvido na linguagem Java chamado Apache Struts que é utilizada por inúmeras enterprises do Top Fortune 100. O que rolou é que a galera de segurança da Equifax cagou para o anuncio que o time do Struts fez em relação a uma falha de segurança e não atualizaram suas aplicações, e só foram corrigir a falha DEPOIS de 2 meses, quando já havia sido atacada. É, certamente não é só no Brasil que muitas empresas são bem amadoras nesse sentido.



Voltando ao assunto do post…

Me desviei um pouco para introduzir melhor um pouco os contextos acima para que a sua analise desse post possa fazer mais sentido, com isso tudo dito, vamos falar agora um pouquinho da parte mais técnica dessa falha.

Um pouquinho sobre a plataforma

Essa aplicação é uma aplicação Node.js rodando com o Express e que usa o MongoDB como banco de dados, e se liguem nos pequenos clientes dessa empresa:

  • Boticário (Grupo Eudora que tem faturamento só de 9 bilhões de reais em 2014)
  • B2W - Submarino/Americanas
  • Marvel

Entre outros. Isso que eu acho incrível, mesmo com clientes desse tamanho, ninguém dentro da empresa parece ser importar com a segurança dos dados, como pode isso? COMO PODE ISSO? Eu acho revoltante, INADMISSIVEL. Esse pensamento de “vamos crescer pra caraleo, o que importa é vender” tá sendo um câncer para as empresas, tudo bem: EU entendo que o objetivo de qualquer empresa é lucrar, mas pelo amor de Deus, façam ao menos o básico.

E sabem o que é o pior de tudo? Eu já havia enviado um email para o CEO anunciando que era possível explorar falhas no site em maio de 2016, ou seja, mais de um ano depois e simplesmente não fizeram nada.

Para que fique claro, no meu email inicial eu não expliquei EXATAMENTE a falha pois eu realmente estava procurando entender como uma empresa iria se comportar em relação a isso, e o CEO me respondeu dizendo que leva segurança a sério e que iria colocar um desenvolvedor em contato comigo (o que de fato aconteceu via email), porém logo em seguida eu tive alguns problemas pessoais e não pude mais acompanhar os meus emails, logo não consegui dar sequencia nas nossas conversas. (E em todo caso, se eu tivesse #morrido RIP, essa parada nunca seria resolvida?)

Mas a questão é: Nesse momento o CEO e CTO e equipe de desenvolvimento deveriam ter feito um overview geral da aplicação e investido o tempo que FOSSE necessário para encontrar essas falhas, se esse time tivesse investido algumas horas EU TENHO CERTEZA que encontrariam: ou então que tivessem me enviados mais emails ou mesmo me telefonado, insistido no contato, do meu ponto de vista isso é o mínimo que uma empresa pode fazer. (O que eu esperava era uma reação tipo: COMO ASSIM alguém acessou nosso ADMIN, COM DADOS DE TODOS NOSSOS CLIENTES E USUARIOS, COMO ASSIM? Vamos atrás desse cara e entender tudo, TUDO!!)

Por questões de transparência, o follow up dos emails:

1 - Primeiro contato: Contato - CEO

2 - Resposta do CEO: Resposta - CEO

3 - Resposta Dev:

Me parece que o CEO repassou a treta para a equipe técnica, mas por algum motivo essa equipe parece não ter dado sequencia na investigação. (Como eu disse, um desenvolvedor entrou em contato comigo por email, mas não tive condições de responder daquele momento em diante). Em todo caso, eles já sabiam de algumas falhas e parecem não ter realmente dedicado tempo para resolver isso. Veja abaixo o quão simples é a falha e como ela poderia ser descoberta rapidamente se um tempo fosse REALMENTE dedicado para procurar. (levando em consideração que conhecem a aplicação MUITO melhor que eu, poderia ser mais rápido ainda)

OBS: Sim, entendo que me procuraram e eu não pude responder naquele momento, mas ainda sim, eles estão prestando um serviço e não deveriam depender somente da minha resposta, e numa dessas se eu tivesse explodido junto com um boeiro no Rio? Vai saber :thinking:

Simbora #hackear, entonces!

Como eu disse, essa aplicação é uma aplicação Node e o banco de dados escolhido é o NoSQL MongoDB. Eu encontrei AS FALHAS quando eu tentei me cadastrar no site, não demorou nem cerca de 30 segundos para que eu pudesse detectar….

Primeira falha: Endpoint permitindo “where” no database

Sei que você já ficou em choque só de ler isso: SIM! Uma coisa é certa: Nunca é uma boa expor um endpoint que permita consultar o banco de dados sem nenhum tipo de filtro, basicamente a aplicação aceita qualquer input e retransmite para o banco de dados.

HTTP Request API

Certo, agora perceba que existem dois parâmetros cruciais: where e limit, sabendo disso e também sabendo que o banco de dados é o MongoDB, que tal tentar uma query pedindo para o banco de dados retornar TODOS os registros de usuários em que a chave email esteja presente?

Pesquisei na doc do Mongo e a query segue a seguinte syntax:

1
Syntax: { field: { $exists: <boolean> } }

Logo: '{ "email": { "$exists": true } }', fiz o encode para enviar tudo corretamente:

1
2
3
// js
encodeURIComponent('{ "email": { "$exists": true } }')
"%7B%20%22email%22%3A%20%7B%20%22%24exists%22%3A%20true%20%7D%20%7D"

E enviei a requisição como:

1
curl 'http://(...)/api/v2/users?limit=1&skip=0&where=%7B%20%22email%22%3A%20%7B%20%22%24exists%22%3A%20true%20%7D%20%7D' -H 'Authorization: Bearer (TOKEN OBTIDO PELO SITE)'

Omiti algumas informações que não são relevantes na resposta, que veio como:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
  "total": 116079,
  "items": [
    {
      "_id": "552401cb60fc6f0039bf61b7",
      "name": "(....)",
      "email": "(...)@gmail.com",
      "avatar": "https://graph.facebook.com/(....)/picture",
      "createdAt": "2015-04-07T16:11:55.076Z",
      "updatedAt": "2016-01-07T16:47:47.943Z",
      "lastLogin": "2016-01-07T16:47:47.936Z",
      "isAdmin": false,
      "facebookId": "790128(...)",
      "accounts": [
        {
          "oAuthUserId": "ID_DO_FACEBOOK",
          "provider": "facebook",
          "name": "(....)",
          "email": "(....)",
          "avatar": "https://graph.facebook.com/ID_DO_FACEBOOK/picture",
          "_id": "56049381afdb87100061eaa2"
        },
        {
          "oAuthUserId": "ID_DO_GOOGLE",
          "provider": "google",
          "name": "(....)",
          "email": "(....)",
          "avatar": "FOTO DO GOOGLE PLUS",
          "_id": "56059d950cb6210f0053a8d1"
        }
      ],
      "__v": 6,
      "id": "552401cb60fc6f0039bf61b7"
    }
  ]
}

CARAI não creio!!!! Ta bém, vamos quebrar por partes as informações que essa resposta me deu:

  • "total": 116079 - Esse é o número total de cadastros no site, nada mal

  • "email": "(...)@gmail.com" - Esse é o email do usuário, ou seja, uma base com 116079 emails válidos para um criminoso usar para Pishing…hmmm

  • "isAdmin": false - HMMM MAS QUE INFORMAÇÃO MAIS IMPORTANTE ESSA MEU QUERIDO…quer dizer que no banco de dados essa é a flag que determina se um usuário é administrador ou não…interessante, voltaremos nisso logo menos.

  • "facebookId": "790128(...)" - Certo…esse site tem integração de login com o FB, isso quer dizer que se eu for um criminoso posso obter mais informações sobre essa pessoa diretamente do feed dela…engenharia social feelings….hm…

  • "accounts": [ { dados da conta do fb }, { dados da conta Google }] - Existe também uma integração com Login via Google, isso quer dizer que além de um novo endereço de email, eu também posso usar essa aprender mais sobre o usuário.

Que maravilha ein? Agora basta alterar o limit na requisição para o mesmo valor total total de usuários do site, bora tentar enviar a requisição e salvar todos os dados num arquivo?

1
2
3
4
5
$ curl 'http://(...)/api/v2/users?limit=116079&skip=0&where=%7B%20%22email%22%3A%20%7B%20%22%24exists%22%3A%20true%20%7D%20%7D' -H 'Authorization: Bearer (TOKEN OBTIDO PELO SITE)' > all_users.json

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13.5M    0 13.5M    0     0   247k      0 --:--:--  0:00:56 --:--:-- 1129k

Dentro de cerca de 56 segundos eu consegui obter TODOS os usuários do site! GZUS! Quanto tempo e dinheiro será que investiram para obter todos esses usuários?(Marketing, servidores, funcionários, café…) Não sei, só sei que todo esse esforço deles foi obtido em menos de 1 minuto, isso porque minha internet é da VIVO e a velocidade não é lá essas coisas(o que você provavelmente já sabe).

OBS: Todos os dados coletados durante essa pesquisa foram deletados apos sua conclusão.

Como esse arquivo ficou com quase 100MB e abrir no editor foi um desastre, eu recorri ao Ruby para ler somente o primeiro MB do arquivo:

1
2
3
4
5
6
7
8
9
10
# Abre arquivo em modo de leitura
all_users = File.open('all_users.json', 'r')

# Escreve o arquivo `all_users_first_1_mb.json` no disco (e na pasta atual) lendo somente os primeiros 1MB do arquivo.
File.open('all_users_first_1_mb.json', 'wb') {|f2| f2.write all_users.read(1024 * 1000) }

# Executa comando no sistema para abrir arquivo no editor
# Se não manja o que o identificador "`"(backticks) faz, leia:
# https://stackoverflow.com/a/18623297
`subl all_users_first_1_mb.json`

Abri o arquivo e corrigi o final para que pudesse ser um JSON válido, depois usei uma extensão do Sublime para JSON Pretty Print de forma mais que ficasse mais legivel para humanos(nois :v:) para que eu pudesse explorar os dados com mais liberdade.

Percebi que tinham emails diferentes entre os usuários(pelas contas associadas pelas integrações do FB e Google) e então decidi que seria uma boa calcular o numero total de emails unicos, contas do Facebook e Google Plus únicas nos dados.
Conforme esperado: Obtive mais emails que o total que a API me retornava que era 116079, somando:

  • emails únicos do sistema(116005)
  • emails únicos do de contas associadas do Facebook(10006)
  • emails únicos de contas associados do Google(3857)

Adicionando todos esses emails em um Set, isto é um elemento somente com registros únicos cheguei ao total de 121530 registros únicos de emails(ou seja 5451 emails a mais do que a API me disse inicialmente), além disso foi possível obter dados como data de aniversário, genero, e local de trabalho(vindos de fb/g+), sendo possível complementar os dados de alguns usuários).

Certo, como um possível atacante eu já poderia ter obtidos dados de todos os usuários além de endereço de emails e informações complementares através das integrações com FB e G+.

Porém, esse foi só a primeira brecha, como eu disse: Essa foi notada logo de cara, dentro dos primeiros segundos navegando no site.

Se você estiver acompanhando o post(e espero que esteja, escrevi pra você!), você deve lembrar que a API me retornou basicamente o documento inteiro do usuário, ou seja, todos os dados que estão salvo na “tabela”(no mundo NoSQL o analogo seria “documento”).
Dentro esses dados, um em especial me chamou a atenção, vamos ver novamente:

  • "isAdmin": false - HMMM MAS QUE INFORMAÇÃO MAIS IMPORTANTE ESSA MEU QUERIDO…quer dizer que no banco de dados essa é a flag que determina se um usuário é administrador ou não…interessante, voltaremos nisso logo menos.

“Logo menos” é agora: Você já deve saber que não deve confiar EM NENHUM dado fornecido pelo client(browser, app, etc) quando recebe uma requisição HTTP, claro que sabe né? Estou certo disso! Confio em você!!

Mas no caso essa aplicação não estava pensando nisso, conforme já falei ela aceita qualquer input no endpoint para buscar usuários no banco de dados, certamente deve também aceitar qualquer atributo quando recebe para atualizar um usuário também, né?(muito provável)

Um dos ataques mais comuns em aplicações web é conhecido como Parameter Injection/Parameter Tempering, para mais informações leia aqui. Essa brecha consiste basicamente em permitir que o client envie um payload e o mesmo seja salvo no banco de dados sem nenhum tipo de validação - geralmente os parametros devem ser whitelisted antes de serem enviados para o banco de dados, por exemplo o Rails oferece proteção contra esse tipo de ataque com strong parameters.
Ou seja, no código de backend provavelmente essa aplicação um código parecido com o seguinte para criar/atualizar os dados do usuário.

1
2
3
4
5
6
7
8
9
10
11
/*
`req.params` é um Hash com todos os parametros recebidos
na requisição HTTP
*/
const app = require('express')

app.post('/users', => (req, res) {
 User.create(params, => (err, user){
  // user
 })
})

Você está vuneravel!! Claro que isso vai depender também da arquitetura do seu banco de dados, porém se você tem uma flag que indica se o usuário é administrador na mesma tabela(ou documento), ai sim você pode estar lascado! Digo, seus usuários…

Eu não explorei essa brecha nesse endpoint especifico, pois a primeira coisa que eu fiz foi criar uma conta com um email qualquer no site e então visualizar as opções que eu tinha(eu geralmente procuro aonde posso editar meu perfil, pois é o lugar ideal para enviar paramêtros especificos e ver como a aplicação se comporta).

Opção para atualizar SOMENTE nome na interface:

Editar Perfil

Alterei meu nome e cliquei em “Editar perfil”(que numa UX suspeita funciona como “enviar”, sdds coerência). Nese momento uma requisição PUT foi enviada para o servidor, contendo um objeto inteiro(embora eu só tenha alterado meu nome):

Request PUT para atualizar dados do usuário

Perceba que o parametro isAdmin user foi enviado para a API, bom, já sabe né? Bora trocar esse false por true e enviar novamente. Pra editar a requisição a forma mais prática é copiar a requisição direto do navegador para curl(eu tô sem nenhum proxy aqui, por exemplo o Charles permite editar as requisições de formais mais prática ainda):

Copy as curl

Ai é só jogar no editor, procurei por isAdmin e dei uma temperada alterando essesvalores para true. Fiz isso e enviei a requisição novamente!! Parece que deu tudo certo, pela resposta:

Request temperado

Dei reload na página e olha só quem deu as caras:

Página com botão de administração

A partir desse momento tive acesso completo ao backoffice, que mostrava informações como a seguir:

Admin - Dashboard Admin - Usuários

O quarto bloco nuncaa carrega porque essa aplicação é uma aplicação suicida: Ela envia milhares de requisições de forma disastrosa por segundo, minha máquina chegou a travar e as requisições demorarem mais de minutos para responder pq uma requisição vai encadeando em cima da outra, Single Page Application não se trata soment do front-end: Você precisa pensar nos seus servidores também, a carga será totalmente diferente:

lerdoooo

Certo, isso quer dizer que além dos dados dos usuários eu possível posso conseguir informações privilegiadas de todas as empresas que eu citei lá no começo do post, como por exemplo: URL de sistemas privados dessas empresas, além de alguns emails internos que podem ser tentados para invadir essas areas privadas, além disso nesse sistema é possível cadastrar “recompensas”, como por exemplo cupom de descontos em algumas lojas.

URLs area restrita

Complicado né? Mas ainda tem mais: Nesse momento eu tinha acessado os dados somente de uma empresa, porém como eu poderia procurar pelos demais clientes dessa empresa?

Essa url do admin segue um padrão tipo: http://site.com/<cliente>/admin, eu precisava descobrir outros valores de <cliente> para poder ter certeza que havia conseguido o controle dos dados de outra empresa….pra minha surpresa existe outro endpoint aonde posso obter os nomes de todos os clientes da aplicação, que maravilha! Com os dados desse endpoint, eu pude acessar cada um dos admins e visualizar os dados de cada empresa.



Vamos falar um pouco de REST??

Você já deve saber que REST é um daqueles jargões que todo dev gosta de encher o peito pra falar sobre né? “Não, porque minha aplicação é toda REST, respondo para verbos! Minha API é modernosa rapaz!!!”

Harram, senta lá Cláudia! Eu sinto que falta também maturidade dos desenvolvedores para entenderem que REST não significa ter endpoints disponiveis para todos os recursos , não faz SENTIDO NENHUM você ter um endpoint do tipo: http://meusite.com/api/v1/users para listar todos os seus usuários, se você precisa fazer isso para alguma interface administrativa, dá um jeito de proteger pra caraleo esse endpoint e de preferencia, se for só pra um admin interno torne acessível somente atraves de uma rede interna, e não tente também ocultar um pouco as informações, por convenção esse endpoint será procurado nas aplicações, olha só o quanto esse dado é sensível cara, olha pra isso!

Desenvolvedores: Por favor, avaliem todas as decisões que vocês tem que tomar quando expõem um endpoint com dados de usuários, com dados de empresas ou qualquer dado sensível. Não somente saia codando antes de entender a sensibilidade dos dados que você está trabalhando.

Olha só nessa aplicação os principais erros que foram cometidos:

  • Endpoints permitido consultas no banco de dados
  • Parameter Injection
  • Níveis de acesso extremamente fracos
  • Exposição de dados sensíveis em lote

Também não simplesmente responda com seu documento(ou tabela) de banco de dados inteiro. Utilize serializers para ter controle total do que está sendo enviado para o cliente nas respostas, e remova todo dado sensível dessas respostas e só retorne quando for necessário.
Essa ideia de retornar o documento inteiro é um tiro no pé muito grande: Todo e qualquer dado adicionado no futuro também será retornado, imagina que daqui a 2 meses te pedem para adicionar o CPF, Dados de conta bancária e outras informações sensíveis, já sabe o que vai rolar né?



Como proteger sua aplicação e seus usuários

Certo, vamos falar de algo bom aqui? Conforme já descrevi acima, as falhas encontradas são muito básicas, e podem ser resolvidas fácilmente. Vamos começar com a primeira falha.

Falha 1 - Endpoint de consulta ao banco de dados

Simplesmente NÃO TENHA. Sério, remova esse endpoint dá sua aplicação AGORA! Se você perceber, essa aplicação usava esse endpoint pra verificar se meu email existia no momento do cadastro/login, é sério. Esse endpoint poderia SIMPLESMENTE ser algo como: http://site.com/api/v1/users/check_email?email=teste@teste.com e PRONTO, poderia retornar somente um valor booleano, e PRONTO.
Essa implementação além de MUITO MAIS SIMPLES é MUITO MAIS SEGURA, além de permitir customizações mais especificas de acordo com o crescimento da aplicalão(eg: caching).

Falha 2 - Retorno de informações sensíveis na resposta

Qual o ganho de retornar um objeto do banco de dados inteiramente para o cliente? Além de consumir muito mais banda de todo mundo - dos servidores da aplicação e do cliente consumido - o que além de tornar todo o trafego do site mais lento, isso expoẽm MUITOS dados sensíveis, como por exemplo a flag que eu já citei isAdmin.
Se essa flag não tivesse sido retornado na resposta, de repente eu nem teria tentado dar continuidade no ataque, pois teria que tentar “adivinhar”(embora existam alguns padrões) o nome desse atributo. Desnecessário retornar isso, é como se você trancasse a porta da sua casa mas deixasse colado na porta o tipo de chave necessária para abrir sua porta. Bom, até aqui tudo bem, né? Só saber dessa informação não garante que ninguém irá conseguir essa chave….

Falha 3 - Não fazer whitelist dos dados enviados pelo client - Parameter Injection

Parameter Injection é uma das falhas mais comuns em aplicações web desde de sempre, até mesmo o Github já se deu mal nessa a uns 6 anos atrás - um cara conseguiu hackear a conta do Rails por lá.

Observe que estamos falando de parameter injection e não de SQL Injection. Para mitigar esse problema você deve SEMPRE(SEMPRE) fazer whitelist de todos os dados que você recebe do client antes de enviar para o banco de dados, ex em Ruby:

1
2
3
4
5
6
7
8
9
10
# Attributos EXPLICITAMENTE permitidos na criação e atualização de um usuário
ALLOWED_USER_ATTRIBUTES = %i(name surname email age)

# Obtem dados enviados pelo client na requisição HTTP
user_params = params[:user].symbolize_keys
# Faz "slice"(corta) os parametros recebidos e somente obtem os atributos explicitamente permitidos
whitelisted_user_params = user_params.slice(*ALLOWED_USER_ATTRIBUTES)

# Salva no do com segurança.
user = User.create(allowed_user_parameters)

É importante que você faça isso em TODOS os endpoints que salvem, deletem ou atualize qualquer dado no banco(basicamente qualquer CRUD). Essa soluçao é tão simples também que não deve custar nada para ser feita. Se você usa Ruby dê uma olhada na minha gem Nifty Services que oferece uma API para trabalhar com Services Objects para operações CRUD e que força OBRIGATORIAMENTE que o desenvolvedor EXPLICITAMENTE defina os atributos permitidos ao criar e atualizar um recurso.
Se por acaso voce não tiver certeza dos parametros que deve fazer whitelist, foque principalmente nesses parametros que concedem acessos privilegiados, como is_admin, isAdmin, admin, role, etc.

Falha 4 - Nível de acesso

Endpoints que expoem dados sensíveis devem exigir autenticação, e além disso autorização - não confundir ambos.
Nunca permita que um usuário acesso um dado somente por que o mesmo está logado, sempre verifique se tal dado realmente pertence a esse determinado usuário e/ou se esse usuário tem realmente permissões de executar essa ação(ex: ler, criar, atualizar, deletar…crud…)

Falha 5 - Endpoints desnecessários

Eu já disse: REST é somente uma arquitetura de software, REST não deve te forçar a expor nenhum endpoint desnecessário, você não precisa ter endpoints para ler ou deletar coisas(por exemplo) enquanto não existir REALMENTE a necessidade uso desses endpoints dentro da sua organiação(ou parceiros). Remova todos esses endpoints inutéis da sua aplicação e ela ainda vai continuar REST, sabia??? REST não é só sobre ter os endpoints, e sim sobre como arquitetar os seus endpoints.



Notas Finais

Sugiro que todos visitem o site da OWASP e visualize o Top 10 de vunerabilidades mais comuns em aplicações web, conforme imagem abaixo, que registra dados do ano de 2013:

OWASP - Top 10



Responsible Disclosure

Entrei em contato com a empresa responsável pelo site no dia 13/05/16 e notifiquei a falha:

Dia que fiz o primeiro contato: 09/04/16
Dia que o contato novamente: 28/09/17
Dia que corrigiram: Não obtive retorno (A falha ainda persiste…)
Dia que responderam: Neváh

OBS: Todos os dados coletados durante essa pesquisa foram deletados apos sua conclusão.



No final das contas

Dei uma verificada no site hoje(22/11/2017) e me parece que eles deletaram inumeros usuários da base de dados e agora restam cerca de 6000 (porém ainda continuam acessíveis!!), e também deletaram os dados de vários clientes (provavelmente pq já não mais clientes, sorte deles!!) No final das contas não fizeram nada e ainda continuam expondo os dados das pessoas, que coisa ein?

Comments