Melhores práticas com access tokens
O que é um access token?
É um objeto que descreve o contexto de segurança de um processo (...)
Fonte: MSDN
E no mundo de APIs?
O processo de autenticação e autorização pode ser caro computacionalmente (consultas a banco de dados, servidores de autenticação externos, criptografia de senha etc)
E no mundo de APIs?
Ao invés de sempre termos essa carga a cada requisição a nossos servidores, podemos ter um único endpoint de autenticação / autorização que irá realizar essa etapa
uma vez e gerar um access token com as informações necessárias para autenticar e autorizar mais rapidamente o cliente nas requisições seguintes
E no mundo de APIs?
Esse token deve possuir um tempo de vida limitado, tanto para diminuir efeitos colaterais caso haja um vazamento quanto porque sua informação pode ficar desatualizada
E no mundo de APIs?
Esse segundo processo pode ser automatizado através de
refresh tokens
Eles são utilizados para regerar um access token automaticamente, sem necessitar da intervenção manual do usuário
Como deixar os tokens seguros?
-
Utilizando algoritmos de criptografia seguros e com assinatura;
- AES-256-GCM, ChaCha20+Poly1305, Ed25519 entre outros
-
Tendo cuidado com implementações de bibliotecas com falhas de segurança;
Como deixar os tokens seguros?
- Não faça commit de chaves e outros segredos, nem deixe-os hardcoded na aplicação
- Não guarde informações muito sensíveis (como senhas e outras credenciais)
- Se precisar armazenar do lado do cliente, utilize cookies seguros (flags
httpOnly
e secure
) ao invés do LocalStorage
Como deixar os tokens seguros?
- Apenas trafegue tokens no cabeçalho ou corpo da requisição, nunca na URL
- Não exiba informações do token em seus logs
Exemplo de implementação
use Lcobucci\JWT\Builder;
$time = time();
$token = (new Builder())
->issuedBy('http://example.com') // Configures the issuer (iss claim)
->permittedFor('http://example.org') // Configures the audience (aud claim)
->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', 1) // Configures a new claim, called "uid"
->getToken(); // Retrieves the generated token
lcobucci/jwt
Bibliotecas
JWT
Implementação mais conhecida de tokens
Bibliotecas
PASETO
Implementação com design "mais seguro" por padrão
Throttling e Rate Limiting
O que é Throttling?
É a desaceleração intencional do processamento de uma requisição para prevenir sobrecarga do servidor
O que é Throttling?
Imagine um endpoint que consuma grande recursos computacionais (como, por exemplo, o processo de autenticação e autorização descritos anteriormente)
O que é Throttling?
Se um agente malicioso identificar esse recurso, ele pode se tornar muito visado para ataques, causando sobrecarga no nosso servidor e podendo gerar paralisação e até queda total do serviço
O que é Throttling?
Nesses casos, podemos configurar que o servidor irá aceitar somente x
requisições em algum(ns) endpoint(s) por um certo período de tempo
O que é Throttling?
Após esse valor x
, as requisições entrarão em uma fila para serem processadas alguns instantes depois, assim que as primeiras tiverem sido liberadas
Mas então o que é Rate Limiting?
Ao contrário do Throttling, em a requisição será processada com um atraso, Rate Limiting é fazer o servidor se recusar
a responder após um certo número de requisições
Mas então o que é Rate Limiting?
Nesses casos, devemos emitir um status HTTP 503 Service Unavailable
ou 429 Too Many Requests
Como essas duas práticas se relacionam entre si?
Geralmente, primeiro aplicamos uma política de Throttling para desacelerar o processamento nas x
primeiras requisições, e após um outro número y
, iremos
simplesmente parar de responder
Onde e como configurar essas políticas?
Você deve configurá-las em seu servidor Web (por exemplo, Apache, IIS ou nginx) ou no seu serviço de DNS (por exemplo, o Cloudflare)
Onde e como configurar essas políticas?
Tomando como exemplo o
nginx, utilizaremos o módulo
ngx_http_limit_req_module
(que implementa o mais conhecido algoritmo desse tipo de prática, o
Leaky Bucket)
Onde e como configurar essas políticas?
limit_req_zone $binary_remote_addr zone=login_zone:10m rate=10r/s;
server {
location /login {
limit_req zone=login_zone burst=5;
# outras configurações padrões do meu bloco location...
}
}
Onde e como configurar essas políticas?
O código anterior irá proteger nosso endpoint /login
, permitindo apenas 10 requisições por segundo por IP (ou seja, 1 a cada 100ms)
Onde e como configurar essas políticas?
Mas também permitimos um burst, permitindo que 5 requisições extras sejam colocadas na fila de processamento antes de serem enviadas para o upstream
Onde e como configurar essas políticas?
Nesse caso, se recebermos de um mesmo IP 10 requisições em um período de 100ms, o que ocorrerá?
- A 1ª requisição será processada instantaneamente
- As 2ª, 3ª, 4ª, 5ª e 6ª requisições serão colocadas em uma fila e serão processadas sequencialmente após o término da anterior
- As 7ª, 8ª, 9ª e 10ª requisições serão negadas
Criptografando e assinando requisições e respostas
Precaução extra
Para usuários avançados e sistemas críticos, podemos adicionar uma camada extra de proteção: criptografar os dados da requisição e da resposta
Precaução extra
Mas, espera aí! Eu já uso HTTPS. Meu dados já estão sendo criptografados usando TLS.
Precaução extra
Após o estabelecimento do protocolo, realmente os dados transitados estão criptografados, mas ainda podemos sofrer um ataque de
Man in the Middle
Man in the Middle
- Existem diversos hops entre o cliente e o servidor. Quem garante que todos os gateways do caminho são seguros?
- Se você não for o administrador da sua rede local, alguém pode instalar uma Autoridade Certificadora em sua máquina e emitir certificados próprios
Man in the Middle
-
Nem todos os sites utilizam HSTS
- Ou seja, pode haver uma conexão HTTP antes do redirecionamento para HTTPS pelo servidor
- Teoria da conspiração: grandes empresas possuem backdoors para bisbilhotar seu tráfego
Precaução extra
Antes de seguir nessa etapa, faça um Threat Modeling e certifique-se que realmente valhe a pena
Compensa instalar um sistema de segurança de última geração em um depósito que não possui algo de extremo valor dentro?
Precaução extra
SIM! Meu sistema é crítico e preciso disso. Ou eu não confio em grandes corporações.
Precaução extra
Você pode exigir que toda requisição tenha seu corpo criptografado pelo cliente, utilizando um segredo em que só vocês dois sabem
Precaução extra
Por exemplo, você pode utilizar uma terceira informação fora o Client ID e o Client Secret e usá-la como chave assimétrica, ou fornecer um certificado digital para seu cliente
Precaução extra
Do lado do servidor, você utiliza essa informação sigilosa para descriptografar o corpo da requisição - se falhar, você emite um erro e para o processamento
Precaução extra
Entretanto, esse processo de descriptografia pode ser muito custoso operacionalmente, podendo ser um outro ponto de ataque DoS (lembre-se do que falamos na seção de Throttling e Rate Limiting).
Você pode, então, utilizar um processo de assinatura digital além da criptografia.
Fluxo de criptografia e assinatura
O cliente...
- Autentica na sua API fornecendo as credenciais
-
Para cada requisição, assina e criptografa os dados (combinação do corpo da requisição + URL);
- Utiliza um algoritmo de hash para assinar os dados
- Criptografa os dados mais a assinatura
- Envia a requisição somente com os dados criptografados
-
Para cada resposta seguinte, ele deve:
- Verificar a assinatura
- Descriptografar o corpo
Fluxo de criptografia e assinatura
A cada requisição recebida, o servidor deve...
- Verificar a assinatura
- Descriptografar o corpo
-
Ao responder à requisição, deve assinar e criptografar os dados (combinação do corpo da requisição + URL);
- Utiliza um algoritmo de hash para assinar os dados
- Criptografa os dados mais a assinatura
- Envia a requisição somente com os dados criptografados