(Parte 3) Segurança em APIs RESTful

Thiago Lima
thiagolima_br
Published in
7 min readMay 9, 2019

--

E aí vamos aprender mais sobre APIs Restful?

Nesse artigo vou falar de um tema polêmico e importante sobre APIs — Segurança.

Já ouvi muita empresa perguntar:

Além disso, indústrias como a bancária, que normalmente é paranóica no assunto segurança, será obrigada a expor APIs ao mercado, o famoso Open Banking até 2020 por uma mudança na legislação.

Portanto, prestem bastante atenção nesse tema. Mas antes, quero colocar alguns pré-requisitos na leitura desse artigo, que são os meus artigos anteriores:

Esses são os conhecimentos básicos que você precisa ter para avançar nesse tema de segurança.

Autenticação vs Autorização

Autenticação é como se você fosse para uma festa, e o segurança exigisse suas credenciais como nome na lista e RG para liberar sua entrada.

Autorização é como se você já estivesse dentro da festa e quisesse subir ao palco do show, mas para isso você precisaria ser autorizado pelo segurança.

Principais métodos de autenticação

Basic Authentication

Basic authentication é um esquema de autenticação bem simples especificado no protocolo HTTP.

O cliente envia uma requisição com o header (Authorization) que contém a palavra Basic e o nome de usuário e senha, separados por dois pontos (:) no formato de base64.

Por exemplo, para autorizar o usuário thiago com senha thiago@123, o client enviaria na requisição, o seguinte header:

Authorization: Basic dGhpYWdvOnRoaWFnb0AxMjM=

Como o formato base64 é muito fácil de ser decodificado, a basic authentication só é recomendada quando são utilizados outros complementos de segurança, como por exemplo, o certificado HTTPS.

OBS: Já vi casos em que é substituido o usuário e senha por um token, mas isso é exceção e não é recomendado pela especificação.

API Keys

API Keys é um método de autenticação que teoricamente veio para resolver alguns problemas do modelo de Basic Authentication.

A ideia do método de API Keys é simples, o servidor gera uma chave de acesso única para o client, e para utilizar a API, o client envia essa chave única em toda requisição.

É um método bem simples e rápido de ser implementado, e durante anos foi o método mais utilizado pelos desenvolvedores.

A grande questão é que esse método serve apenas para autenticação, e não para autorização, ou seja, em teoria um usuário com uma Key válida tem acesso a todas as operações de uma API.

Além disso, ela funciona como qualquer requisição HTTP, e se algum ponto de rede estiver inseguro, ela pode ser facilmente interceptada e utilizada para acesso indevido da API.

Normalmente essa key é utilizada no header, por exemplo, imagine que você recebeu do servidor a seguinte key: "thi123456", nesse sentido para eu me autenticar na API eu faria uma requisição com o seguinte header:

Api-key: thi123456

Vale ressaltar que o parâmetro de header pode variar de acordo com a API, ou seja, pode ser "x-Api-key" por exemplo, ou então, pode ser que o envio dessa key seja via Query String, e não pelo header, algo menos seguro ainda, pois fica extremamente visível para quem vai atacar.

OAuth

O OAuth está na sua versão 2.0, e não é apenas um método de autenticação, e sim um protocolo completo com diversas especificações de segurança.

Ele é extremamente útil para o processo de autenticação e autorização, e por isso, atualmente é o método mais recomendado para o cenário de APIs.

Vamos entender alguns conceitos básicos do OAuth 2:

  • Resource Owner: entidade dona do recurso, ou seja, que é capaz de controlar o acesso a um recurso. Normalmente é o próprio usuário.
  • Resource Server: servidor que possui os recursos, e por sua vez, recebe as requisições.
  • Authorization Server: servidor que gera tokens de acesso para permitir que o client acesse os recursos autorizados pelo resource owner.
  • Client: aplicação que acessa os recursos do resource server.

Para entender melhor, vamos supor que você desenvolveu uma aplicação que utiliza dados do usuário do Facebook, então vamos simular como seria um fluxo básico de autenticação via OAuth 2.0:

  1. O usuário acessa seu site ou app que teria um botão de "integre ao facebook", sendo que o seu site ou app seria o client.
  2. Ao clicar no botão, o usuário é redirecionado para a tela de login do Facebook (authorization server).
  3. Após o usuário informar as credenciais, o Facebook fornece um código de acesso ao client.
  4. Então o client solicita autorização aos recursos (endpoints da API do Facebook) para o resource owner (que é o próprio usuário) enviando o código de acesso recebido anteriormente.
  5. O authorization server por sua vez, verifica se o código de acesso é valido, e caso positivo, ele gera um token de acesso para retornar ao client.
  6. Por último, agora que o client já tem o token de acesso e autorização aos recursos, então a cada requisição, o resource server (API do facebook) irá responder com os dados protegidos.

Como é um assunto denso, vou deixar aqui o link de um ótimo artigo que explica em detalhes esse protocolo.

Outros assuntos acerca da especificação do oAuth e que são interessantes para implementação:

OpenID Connect: Extensão da funcionalidade de autenticação do OAuth. Como o OAuth foi projetado para autorização, o OpenID Connect acaba sendo um ótimo complemento na segurança de APIs, conseguindo ajudar no sentido de provar que o usuário é realmente quem ele diz que é.

JWT: Formato de token seguro que utiliza JSON como base.

SAML

Temos também o SAML, ou Security Assertion Markup Language. Que é um padrão aberto que permite que provedores de identidade (IDP) passem credenciais de autorização para provedores de serviços (SP).

Em outras palavras, o usuário pode usar as mesmas credenciais para entrar em aplicações diferentes.

Na prática, o SAML ativa o Single Sign-On (SSO), algo bem interessante para a experiência dos usuários, pois eles fazem o login uma única vez e consegue navegar em todos as aplicações com o padrão implementado.

Não vejo outro cenário de aplicação do SAML além de casos que o login único seja premissa, pois ele utiliza o XML na comunicação, que já é algo ultrapassado para o desenvolvimento WEB que estamos vivendo atualmente.

Se quiser entender mais sobre as diferenças e casos de uso comparados ao OAuth, leia esse artigo.

Boas práticas de segurança

Em uma visão direta ao ponto, essas são as principais recomendações de segurança para a grande maioria dos cenários de APIs RESTful:

Mantenha simples a sua implementação

Pense sempre na experiência do desenvolvedor que irá consumir, muitas APIs perdem engajamento da comunidade pela complexidade no consumo devido a implementações de segurança.

Sempre utilize HTTPS

Essa é uma dica básica de segurança na WEB para você manter as mensagens trafegadas seguras e criptografadas, dificultando qualquer interceptação da requisição.

É natural que haja uma queda de performance, porém, se você estiver utilizando HTTP 2 existem diversos workarounds de otimização.

Não exponha dados sensíveis na URL

Uma má prática comum é a passagem de dados relativos a segurança via URL. Por exemplo:

GET https://api.test.com/orders/?apiKey=thiago1234

Isso facilita muito a vida de alguém com más intenções na sua API.

Considere a utilização de OAuth

O OAuth hoje é sem dúvidas a especificação mais completa para APIs RESTful, por isso, utilize tudo que há de melhor no OAuth, apenas tomem muito cuidado para não deixar a implementação muito complexa e impactar negativamente a experiência do desenvolvedor que irá consumir sua API.

Utilize o Rate Limit

Essa é uma prática interessante e que pode ajudar a prevenir ataques que focam em deixar sua infraestrutura indisponível por uma quantidade alta de requisições.

Com a implementação desse header você consegue restringir o número de requisições do client.

Com a implementação, você sempre retorna os seguintes headers na resposta de uma requisição:

  • X-Rate-Limit-Limit — Número de requisições permitidas durante um período específico (dia, hora, etc)
  • X-Rate-Limit-Remaining —Número de requisições restantes do período corrente
  • X-Rate-Limit-Reset — Segundos restantes do período corrente

Além disso, em casos que o client ultrapasse o limite de requisições, você retorna o status code 429 — Too Many Requests.

Timestamp na requisição

Se for uma API em que segurança é um ponto crítico, uma boa dica é criar um header customizado com o timestamp. Assim o server pode comparar o timestamp atual, e aceitar apenas as requisições que estiverem próximas a um período de tempo (por exemplo: 2 minutos).

Isso é um procedimento simples, e que pode prevenir ataques básicos de replay em tentativas de força bruta.

Valide o parâmetros da requisição

Por questões de segurança, sempre valide os paramêtros da requisição antes da execução da lógica do negócio.

Caso a requisição esteja com parâmetros não especificados na sua documentação, rejeite imediatamente a requisição, pois pode ser indício de um ataque malicioso.

Além disso, para não impactar negativamente a experiência de quem não está mal intencionado, retorne mensagens de erros claras sobre o assunto, e disponibilize exemplos da requisição feita corretamente.

Utilize uma ferramenta de API Gateway

Existem diversas ferramentas que facilitam as implementações dessas recomendações centralizando toda a inteligência de segurança em uma camada específica de arquitetura.

Nesse desenho conseguimos entender esse modelo:

Algumas ferramentas recomendadas para essa arquitetura: LinkApi, Kong e WSO2 e Apigee.

E é isso aí meus amigos developers, encerramos mais um artigo sobre APIs RESTFul com um tema importantíssimo que é segurança.

Espero que tenham gostado, e até o próximo artigo que será sobre versionamento de APIs, então fiquem ligados!

--

--