Skip to main content

Como proteger uma API REST?

Escrito por
blog feature snyk container custom base recommendations

27 de junho de 2024

0 minutos de leitura
How to Secure a REST API

Como desenvolvedores, muitas vezes trabalhamos com APIs REST ao integrar sistemas de terceiros ou conectar sistemas de front-end e back-end no trabalho. As APIs — e, em particular, as APIs REST — são fundamentais para as aplicações web modernas, pois permitem criar, ler, atualizar e excluir dados por HTTP. No entanto, como qualquer tecnologia, elas também trazem seus próprios desafios de segurança. Vamos analisar esses desafios e entender como proteger aplicações que usam APIs REST.

O que é uma API REST?

As APIs REST (transferência representacional de estado) são um conjunto de convenções para projetar aplicações em rede. Elas usam protocolos HTTP para enviar e receber dados e podem ser usadas com qualquer linguagem de programação capaz de enviar solicitações HTTP. Isso as torna extremamente versáteis e muito usadas no desenvolvimento web.

No entanto, essa versatilidade também as torna alvo de ameaças cibernéticas. Por isso, você deve sempre priorizar o desenvolvimento de software seguro, por exemplo, implementando os controles proativos do OWASP Top 10. Sem as medidas de segurança adequadas, as APIs REST podem expor dados confidenciais ou até servir de porta de entrada para que invasores comprometam seu sistema.

Ameaças comuns à segurança de APIs REST

Há várias ameaças comuns à segurança de APIs REST que os desenvolvedores devem conhecer:

  1. Ataques de injeção: acontecem quando um invasor envia dados maliciosos como parte de um comando ou consulta, induzindo o interpretador a executar comandos não previstos ou acessar dados sem autorização. Por exemplo, um ataque de injeção de SQL pode manipular as consultas ao banco de dados da sua API, causando vazamentos ou alterações não autorizadas de dados.

  2. Falhas de autenticação: se os mecanismos de autenticação da sua API forem implementados incorretamente, invasores poderão se passar por outros usuários ou até obter privilégios administrativos. Foi o que aconteceu na violação de dados do Reddit em 2018, quando hackers conseguiram contornar a autenticação de dois fatores baseada em SMS.

  3. Exposição de dados confidenciais: as APIs costumam lidar com dados confidenciais, como credenciais de usuários ou informações pessoais. Se esses dados não forem protegidos adequadamente, poderão ser interceptados ou vazados, causando graves violações de privacidade.

  4. Ausência de limitação de taxa: sem limitar a taxa de solicitações, sua API fica vulnerável a ataques de força bruta, nos quais um invasor faz várias tentativas para adivinhar credenciais de usuários ou sobrecarregar seu sistema. Esse foi um dos principais fatores do ataque à Dyn em 2016, que derrubou grandes sites como Twitter e Netflix. A limitação de taxa costuma ser implementada como parte do middleware e é considerada uma boa prática para proteger gateways de API.

  5. Dependências inseguras: se sua API depende de bibliotecas ou frameworks de terceiros com vulnerabilidades conhecidas, os invasores podem explorá-las. Esse é um problema comum em software de código aberto, como ocorreu na violação de dados da Equifax em 2017, quando uma vulnerabilidade no Apache Struts foi explorada.

Você pode reduzir essas ameaças seguindo as boas práticas de segurança para APIs REST, como usar técnicas de programação segura, implementar mecanismos robustos de autenticação e autorização, criptografar dados confidenciais e usar ferramentas como Snyk Code e Snyk Open Source para detectar e corrigir vulnerabilidades no seu código e nas dependências.

Nos próximos capítulos, vamos explorar essas boas práticas e mostrar como você pode implementá-las para proteger suas aplicações que usam APIs REST.

1. Implemente mecanismos robustos de autenticação e autorização

Ao proteger uma API REST, implementar mecanismos robustos de autenticação e autorização é a primeira linha de defesa. Isso garante que somente usuários autenticados e autorizados possam acessar os endpoints da API.

A autenticação segura é o processo de confirmar se um usuário é quem diz ser. Para proteger uma API REST, é essencial garantir que o processo de autenticação seja seguro e impeça acessos não autorizados. Por exemplo, em 2019, uma violação de dados no Facebook expôs as informações pessoais de quase 50 milhões de usuários. A causa foi um problema no mecanismo de autenticação, o que destaca a importância de uma autenticação segura.

O Snyk Code pode ajudar você a detectar possíveis vulnerabilidades de autenticação na sua base de código, como credenciais codificadas diretamente ou ausência de limitação de taxa, que podem levar a ataques de força bruta.

Como usar OAuth 2.0 e JSON Web Tokens (JWT)

OAuth 2.0 é um protocolo que permite que um usuário autorize um site ou aplicativo de terceiros a acessar suas informações sem compartilhar suas credenciais. Ele é amplamente usado por sua escalabilidade e simplicidade.

No contexto da autenticação, JSON Web Tokens (JWT) são um mecanismo popular para a troca segura de informações entre partes na forma de um objeto JSON. As informações contidas em um JWT podem ser verificadas e consideradas confiáveis porque são assinadas digitalmente.

Veja um exemplo de como usar JWT para autenticação em uma API REST com Node.js:

const jwt = require("jsonwebtoken");

// User login
app.post("/login", (req, res) => {
  // Authenticate user
  // ...

  // Generate JWT
  const token = jwt.sign({ userID: user.id }, "your-secret-key");

  // Return token
  res.json({ token });
});

// Secure endpoint
app.get("/secure", (req, res) => {
  // Get token from headers
  const token = req.headers["x-access-token"];

  // Verify token
  jwt.verify(token, "your-secret-key", (err, decoded) => {
    if (err) {
      return res.sendStatus(403);
    }

    // Access granted
    // ...
  });
});

Boas práticas para gerenciar tokens de acesso

Os tokens de acesso são as chaves da sua API e precisam ser gerenciados com segurança. Confira algumas boas práticas:

  • Expiração do token: os tokens de acesso devem ter uma duração curta. Assim, o impacto será menor caso um token seja comprometido.

  • Armazenamento do token: evite armazenar tokens de acesso no armazenamento local, pois invasores podem acessá-los facilmente se a aplicação tiver uma vulnerabilidade de cross-site scripting (XSS). Em vez disso, use mecanismos de armazenamento seguros, como cookies HTTP-only com propriedades de segurança habilitadas (SameSite, Secure e HttpOnly, entre outras boas práticas).

  • Transmissão do token: sempre transmita tokens por canais seguros. Use HTTPS em vez de HTTP para evitar ataques do tipo man-in-the-middle.

O Snyk Open Source pode ajudar você a detectar vulnerabilidades nas dependências de código aberto usadas para gerenciar tokens, garantindo que seus tokens de acesso sejam gerenciados por uma biblioteca sem vulnerabilidades de segurança conhecidas. Para saber mais sobre segurança de aplicações e se antecipar às ameaças, crie uma conta gratuita na Snyk.

2. Proteja os dados em trânsito e em repouso

Proteger os dados, tanto em trânsito quanto em repouso, é essencial para proteger uma API REST. Nesta seção, você encontrará boas práticas para proteger dados em trânsito e em repouso.

HTTPS (Hypertext Transfer Protocol Secure) é uma medida de segurança essencial para qualquer API. Ele garante que os dados transferidos entre o cliente e o servidor sejam criptografados e não possam ser interceptados por invasores.

A maioria dos provedores de nuvem e serviços de hospedagem oferece um certificado SSL gratuito, que você pode usar para habilitar HTTPS na sua API REST. No entanto, se precisar implementar a terminação SSL no próprio código da aplicação para a comunicação entre microsserviços internos ou por outros motivos, veja um exemplo de como forçar o uso de HTTPS em uma aplicação Flask com a extensão Flask-SSLify do pacote Python:

from flask import Flask, request
from flask_sslify import SSLify

app = Flask(__name__)
sslify = SSLify(app)

@app.route('/')
def index():
    return "Hello, World!"

if __name__ == '__main__':
    app.run()

No trecho de código Python acima, usamos a extensão Flask-SSLify para forçar o uso de HTTPS em uma aplicação Flask. Essa é uma das formas de proteger sua API REST com HTTPS.

Métodos de criptografia de dados

A criptografia de dados é outro aspecto crucial para proteger uma API REST. Ela garante que, mesmo que um invasor consiga acessar seus dados, não poderá lê-los sem a chave de descriptografia.

Um método popular de criptografia de dados é o AES (Advanced Encryption Standard). O AES é um algoritmo de criptografia simétrica amplamente usado por sua segurança e eficiência.

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_GCM)
plaintext = b'This is a test.'
ciphertext = cipher.encrypt(plaintext)

print('Ciphertext:', ciphertext)

No trecho de código Python acima, usamos a biblioteca PyCryptoDome para criptografar dados com AES, usando uma chave de 128 bits e o modo de operação GCM (Galois/Counter Mode).

Como usar cabeçalhos HTTP para reforçar a segurança

Os cabeçalhos HTTP podem reforçar a segurança da sua API REST. Cabeçalhos como Content Security Policy (CSP) e X-Content-Type-Options ajudam a evitar vulnerabilidades web comuns.

CSP é um cabeçalho de segurança que ajuda a prevenir ataques de cross-site scripting (XSS), controlando os recursos que uma página web pode carregar.

X-Content-Type-Options é outro cabeçalho de segurança que impede a detecção automática do tipo MIME, uma técnica usada por invasores para enganar o navegador e fazê-lo executar scripts maliciosos.

@app.after_request
def apply_caching(response):
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["Content-Security-Policy"] = "default-src 'self'"
    return response

No trecho de código Python acima, definimos os cabeçalhos X-Content-Type-Options e CSP em uma aplicação Flask.

Recomendo muito que você leia sobre como uma Content Security Policy pode prevenir XSS e outras vulnerabilidades.

3. Valide e sanitize os dados de entrada

Uma das etapas mais importantes para proteger uma API REST é validar e sanitizar os dados de entrada. Isso é essencial para prevenir ataques como a injeção de SQL.

A injeção de SQL é uma ameaça comum à segurança que explora vulnerabilidades nos campos de entrada de dados de uma aplicação. Nesse tipo de ataque, um invasor pode manipular consultas SQL inserindo código SQL malicioso nos campos de entrada da aplicação, o que permite acessar ou manipular dados sem autorização. De forma semelhante, ataques de injeção de NoSQL podem ocorrer quando um invasor manipula uma consulta a um banco de dados NoSQL ao inserir código malicioso nos campos de entrada da aplicação.

A equipe de pesquisa de segurança da Snyk já publicou alertas de segurança que identificaram a popular biblioteca ORM Squelize como vulnerável a ataques de injeção de SQL. Isso reforça a importância de validar e sanitizar os dados de entrada e monitorar suas bibliotecas de código aberto em busca de vulnerabilidades (você pode usar o Snyk Open Source gratuitamente para ajudar com isso).

Implementação de técnicas de validação de entrada

Para reduzir esses riscos, é essencial implementar técnicas de validação de entrada. A validação garante que somente dados formatados corretamente entrem no seu sistema. Por exemplo, se a idade de um usuário deve ser um número, o sistema deve rejeitar qualquer entrada que não seja numérica.

Veja um exemplo simples de validação de entrada em JavaScript:

function validateAge(age) {
  if (isNaN(age)) {
    throw new Error("Invalid input: age must be a number");
  }
}

Melhor ainda, você pode usar uma biblioteca como Zod ou Joi para validar entradas de forma mais robusta e fácil de manter. Essas bibliotecas definem um esquema esperado para os dados de entrada e os validam com base nesse esquema. Elas são mais rápidas e confiáveis do que escrever sua própria lógica de validação. Para quem usa TypeScript, Zod é uma ótima opção, pois foi desenvolvido pensando nessa linguagem.

Além de validar as entradas, você também deve sanitizar os dados para neutralizar possíveis efeitos nocivos de entradas maliciosas. A sanitização remove ou modifica dados para evitar que sejam usados de forma prejudicial.

Veja um exemplo simples de sanitização de dados em JavaScript:

function sanitizeString(str) {
  return str.replace(/<[^>]*>?/gm, "");
}

No entanto, não exagere na sanitização com RegEx. Ela não é uma solução infalível e pode ser contornada por invasores. Em vez disso, use bibliotecas utilitárias como validator.js, disponível no ecossistema npm, que oferece uma ampla variedade de métodos de validação para diferentes tipos de dados. Ao escrever uma RegEx, você pode deixar passar casos extremos e até introduzir uma vulnerabilidade de segurança conhecida como negação de serviço por expressão regular (ReDoS). A Snyk já publicou uma análise detalhada sobre a popular vulnerabilidade ReDoS do UAParser.js.

Validar e sanitizar manualmente cada dado pode ser trabalhoso. Felizmente, existem ferramentas que automatizam essas tarefas. Uma delas é o Snyk Code, uma solução de teste de segurança estática de aplicações (SAST) que ajuda você a identificar e corrigir vulnerabilidades no código, inclusive as relacionadas à validação e sanitização de entradas.

4. Use dependências seguras

Ao pensar em como proteger uma API REST, é fundamental prestar atenção às dependências usadas pela sua aplicação. Nas seções anteriores, mencionamos várias bibliotecas e frameworks populares que já foram identificados como vulneráveis a ameaças de segurança.

Nesta seção, vamos destacar os possíveis riscos de usar bibliotecas vulneráveis, mostrar como usar o Snyk Open Source para detectá-las e apresentar estratégias para manter suas dependências atualizadas.

Os riscos de usar bibliotecas vulneráveis

As dependências são como os blocos que compõem sua aplicação. Mas, assim como um tijolo frágil pode comprometer a estrutura de um prédio, uma biblioteca vulnerável pode representar sérios riscos de segurança para sua API REST.

Por exemplo, a famosa violação de dados da Equifax, em 2017, foi atribuída a uma vulnerabilidade no Apache Struts, um framework de código aberto para criar aplicações web em Java. A violação expôs os dados pessoais de 147 milhões de pessoas, reforçando a importância fundamental de usar dependências seguras.

// Example of a vulnerable Apache Struts configuration
<struts>
  <constant name="struts.devMode" value="true" />
</struts>

No exemplo acima, struts.devMode está definido como true, o que pode expor informações confidenciais e deve ser evitado em ambientes de produção.

O modo de desenvolvimento (devMode) do Apache Struts foi criado para desenvolvimento e depuração. Quando devMode está ativado, o framework oferece registros mais detalhados, relatórios de erros e recursos para recarregar configurações. Esses recursos são úteis durante o desenvolvimento, mas podem expor informações confidenciais e criar vulnerabilidades de segurança se forem ativados em um ambiente de produção.

Por exemplo, ativar devMode pode causar:

  • A exibição de mensagens de erro detalhadas para os usuários, que podem revelar informações sobre a estrutura da aplicação, a tecnologia usada ou até mesmo linhas de código e caminhos específicos que podem ser explorados.

  • O recarregamento automático de configurações, que pode ser explorado para alterar o comportamento da aplicação sem precisar reiniciá-la.

  • Maior consumo de recursos devido ao registro e processamento adicionais, o que pode afetar o desempenho e a estabilidade.

Por isso, uma prática recomendada de segurança é garantir que devMode esteja definido como false em ambientes de produção para reduzir esses riscos.

Use Snyk Open Source para detectar dependências vulneráveis

Para reduzir o risco de usar bibliotecas vulneráveis, é essencial ter um sistema robusto para detectar e gerenciar essas vulnerabilidades. É aí que entra Snyk Open Source.

Snyk Open Source é uma ferramenta que ajuda você a identificar e corrigir vulnerabilidades nas suas dependências de código aberto. Ela oferece um banco de dados abrangente de vulnerabilidades conhecidas e monitora continuamente suas dependências para alertar você sobre novos riscos.

# Example of using Snyk Open Source to scan your project for vulnerabilities
snyk test

No exemplo acima, o comando snyk test analisa seu projeto em busca de vulnerabilidades e oferece recomendações práticas para corrigi-las. Os resultados da análise são exibidos no terminal (ou no painel da Snyk, se você estiver usando a interface web da Snyk) e incluem detalhes sobre as vulnerabilidades, sua gravidade e as correções sugeridas. Veja um exemplo de saída para uma aplicação Java com Spring que usa uma versão vulnerável do Apache Struts:

Testing /path/to/your/project...

✗ High severity vulnerability found in org.apache.struts:struts2-core@2.3.20
  Description: Remote Code Execution
  Info: https://snyk.io/vuln/SNYK-JAVA-ORGAPACHESTRUTS-31560
  Introduced through: org.apache.struts:struts2-core@2.3.20
  From: org.apache.struts:struts2-core@2.3.20 > org.apache.struts:struts2-core@2.3.20
  Remediation:
    Upgrade direct dependency org.apache.struts:struts2-core@2.3.20 to org.apache.struts:struts2-core@2.3.24

Tested 123 dependencies for known vulnerabilities, found 1 vulnerabilities, 1 vulnerable paths.

Estratégias para manter as dependências atualizadas

Manter suas dependências atualizadas é essencial para proteger sua API REST. Confira algumas estratégias para gerenciá-las com eficiência:

  1. Verifique se há atualizações regularmente: Crie o hábito de verificar as atualizações das suas dependências com frequência. Você pode fazer isso manualmente ou usar ferramentas como a Snyk para automatizar o processo.

  2. Adote uma estratégia de versionamento: Escolha uma estratégia que equilibre a necessidade de usar os recursos mais recentes com a estabilidade da sua aplicação. O versionamento semântico é uma abordagem popular que usa números de versão para indicar o tipo e o impacto das mudanças.

  3. Automatize as atualizações sempre que possível: Automatizar as atualizações das dependências pode poupar bastante tempo e reduzir o risco de erros humanos. Você pode configurar a Snyk para abrir automaticamente pull requests com atualizações e patches seguros.

# Example of using Snyk to automate dependency updates
snyk monitor

No exemplo acima, o comando snyk monitor monitora continuamente seu projeto e abre automaticamente pull requests com atualizações e patches seguros. Seguindo essas práticas recomendadas, você evita que suas dependências se tornem o ponto fraco da segurança da sua API REST. Lembre-se: quando o assunto é "como proteger uma API REST", cada detalhe importa, e dependências seguras são uma peça fundamental.

Lembre-se: proteger sua API REST envolve mais do que apenas validar e higienizar os dados de entrada. É um processo contínuo que exige monitoramento e atualizações regulares. Seguindo essas práticas recomendadas e usando ferramentas como a Snyk, você pode melhorar significativamente a segurança da sua API REST.

Pronto para começar a proteger sua API REST? Cadastre-se na Snyk hoje mesmo.

Leia mais

Blog

Modelos de ponta encontraram as vulnerabilidades. Só o atacante encontrou as cadeias.

A análise estática encontrou as falhas, mas só os testes de ataque em aplicações ativas provaram como elas poderiam ser encadeadas para causar invasões. Uma comparação entre Evo COS, Claude Security e Claude Code Security.

feature insights context
Blog

Os ataques autônomos já chegaram. A defesa precisa acompanhar o ritmo.

Os atacantes autônomos estão reduzindo o tempo disponível para a defesa. Saiba como a descoberta, a correção, a validação e a prevenção contínuas ajudam as equipes de segurança a acompanhar esse ritmo.

Blog

Por que agentes de programação com IA continuam criando falhas de controle de acesso

Agentes de programação com IA podem gerar uma lógica de autorização que compila e passa pela revisão, mas permite que um tenant acesse os dados de outro. Saiba por que é difícil detectar falhas de controle de acesso e como evitá-las.