Como faço para proteger chamadas de API REST?

91

Estou desenvolvendo o aplicativo da web restful que usa alguma estrutura da web popular no backend, digamos (rails, sinatra, flask, express.js). Idealmente, quero desenvolver o lado do cliente com Backbone.js. Como deixo apenas meu lado do cliente javascript interagir com essas chamadas de API? Não quero que essas chamadas de API sejam públicas e sejam chamadas curlou simplesmente inserindo o link no navegador.

knd
fonte
Todas as suas chamadas de API exigem um token que é passado para o cliente quando sua página é exibida?
hajpoj
O SDK javascript do Amazon AWS usa URL de objeto pré-assinado: - docs.aws.amazon.com/AmazonS3/latest/dev/…
rjha94

Respostas:

90

Como primeiro princípio, se sua API for consumida por seu cliente JS, você deve assumir que é público: um depurador JS simples coloca um invasor em uma posição, onde ele pode enviar uma solicitação idêntica byte a byte de um ferramenta de sua escolha.

Dito isso, se eu li sua pergunta corretamente, não é isso que você deseja evitar: O que você realmente não quer que aconteça é que sua API seja consumida (em uma base regular) sem que seu cliente JS esteja envolvido. Aqui estão algumas idéias sobre como, se não aplicar, pelo menos incentivar o uso do seu cliente:

  • Tenho certeza, sua API tem algum tipo de campo de autenticação (por exemplo, Hash computado no cliente). Se não, dê uma olhada nesta pergunta SO . Certifique-se de usar um salt (ou mesmo uma chave de API) que é fornecido ao seu cliente JS em uma sessão base de (aot hardcoded). Dessa forma, um consumidor não autorizado de sua API é forçado a trabalhar muito mais.

  • Ao carregar o cliente JS, lembre-se de alguns cabeçalhos HTTP (vem à mente o agente do usuário) e o endereço IP e peça uma reautenticação caso eles mudem, utilizando listas negras para os suspeitos do costume. Isso força o invasor a fazer seu dever de casa mais detalhadamente novamente.

  • No lado do servidor, lembre-se das últimas chamadas de API e, antes de permitir outra, verifique se a lógica de negócios permite a nova agora: Isso nega a um invasor a capacidade de concentrar muitas de suas sessões em uma sessão com seu servidor: Em combinação com as outras medidas, isso tornará o agressor facilmente detectável.

Posso não ter dito isso com a clareza necessária: considero impossível tornar completamente impossível para um agressor consumir seu serviço, mas você pode dificultar tanto que pode não valer a pena o incômodo.

Eugen Rieck
fonte
esta é uma informação útil, mas e se eu quiser fazer alguma autenticação da minha API de back-end para outro aplicativo de API como um servidor separado, para simplificar minha pergunta, eu quero que meu back-end aka node.js envie uma solicitação de busca para outro back- servidor final que é meu, por alguns motivos isso é necessário, mas eu quero proteger as chamadas da API, pois ele pode acessar dados confidenciais e não posso usar sessões ou jwt porque não consigo armazená-los no navegador.
A pirâmide de
@Thepyramid Não importa o que a chamada de API faz no lado do servidor, especialmente se o lado do servidor faz outra chamada de API de segundo nível. O importante é tratar seu servidor não como um proxy, mas como um aplicativo.
Eugen Rieck de
você pode explicar mais como fazer como um aplicativo, não como proxy
A pirâmide de
1
O que quero dizer é: para obter uma quantidade decente de segurança, você precisa empregar todas as ferramentas que um webapp possui: sessões, um banco de dados de autenticação, uma lógica de negócios. Se não fizer isso e apenas tratar seu servidor como uma forma de passar solicitações para outro servidor, você o está usando apenas como um proxy para esse outro servidor e está limitado por qualquer segurança que o outro servidor ofereça.
Eugen Rieck
1
@PirateApp Um invasor pode simplesmente ignorar os cabeçalhos CSRF. Eles funcionam apenas se o dispositivo final for um navegador sem patch
Eugen Rieck
12

Você deve implementar algum tipo de sistema de autenticação. Uma boa maneira de lidar com isso é definir algumas variáveis ​​de cabeçalho esperadas. Por exemplo, você pode ter uma chamada de API de autenticação / login que retorna um token de sessão. Chamadas subsequentes para sua API esperarão que um token de sessão seja definido em uma variável de cabeçalho HTTP com um nome específico como 'your-api-token'.

Como alternativa, muitos sistemas criam tokens de acesso ou chaves que são esperados (como youtube, facebook ou twitter) usando algum tipo de sistema de conta API. Nesses casos, seu cliente teria que armazená-los de alguma maneira no cliente.

Em seguida, é simplesmente uma questão de adicionar uma verificação para a sessão em sua estrutura REST e lançar uma exceção. Se possível, o código de status (para ficar tranquilo) seria um erro 401.

gview
fonte
8
Embora não haja nada que os impeça de olhar para os cabeçalhos e reproduzi-los.
cdmckay
1
@cdmckay - Um token deve corresponder a um token armazenado em uma sessão. A simples reprodução do cabeçalho resultará em uma resposta "Não autorizado" se vier de uma sessão diferente.
Andrei Volgin
3
Eles ainda podem usar a mesma sessão e alterar as solicitações antes de serem enviadas para a API ... ou mesmo usando o console em tempo de execução gerar uma chamada com cabeçalhos / campos correspondentes modificando apenas as partes que você precisa ...
Potter Rafed
2
@PotterRafed: se um usuário acessa sua própria sessão válida, isso é chamado usando um aplicativo, não o atacando. O objetivo da autenticação é impedir o acesso a sessões / dados de outros usuários .
Andrei Volgin,
@AndreiVolgin sim, justo, mas ainda é uma vulnerabilidade
Potter Rafed
9

Existe um padrão aberto agora chamado "JSON Web Token",

consulte https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) é um padrão aberto baseado em JSON (RFC 7519) para a criação de tokens que afirmam um certo número de declarações. Por exemplo, um servidor pode gerar um token com a declaração "conectado como administrador" e fornecê-lo a um cliente. O cliente pode então usar esse token para provar que está conectado como administrador. Os tokens são assinados pela chave do servidor, para que o servidor possa verificar se o token é legítimo. Os tokens são projetados para serem compactos, seguros para URL e utilizáveis, especialmente no contexto de logon único (SSO) do navegador da web. As declarações JWT podem ser normalmente usadas para passar a identidade de usuários autenticados entre um provedor de identidade e um provedor de serviços, ou qualquer outro tipo de declaração conforme exigido pelos processos de negócios. [1] [2] Os tokens também podem ser autenticados e criptografados. [3] [4]

bbozo
fonte
O que impediria um usuário de copiar seu token e usá-lo em qualquer outra resposta?
Ulad Kasach
1
@UladKasach para ser honesto, nunca fui muito fundo neles, mas afaik eles podem expirar, são exclusivos para o seu usuário e criptografados por SSL (que você está praticando), é exatamente a mesma ideia por trás do
oauth
3

Com licença, @MarkAmery e Eugene, mas está incorreto.

Seu aplicativo js + html (cliente) em execução no navegador PODE ser configurado para excluir chamadas diretas não autorizadas para a API da seguinte forma:

  1. Primeira etapa: Configure a API para exigir autenticação. O cliente deve primeiro se autenticar por meio do servidor (ou algum outro servidor de segurança), por exemplo, pedindo ao usuário humano que forneça a senha correta.

Antes da autenticação, as chamadas para a API não são aceitas.

Durante a autenticação, um "token" é retornado.

Após a autenticação, apenas as chamadas API com o "token" de autenticação serão aceitas.

É claro que, neste estágio, apenas usuários autorizados que possuem a senha podem acessar a API, embora se eles forem programadores que estão depurando o aplicativo, eles podem acessá-lo diretamente para fins de teste.

  1. Segunda etapa: Agora configure uma API de segurança extra, que deve ser chamada em um curto limite de tempo após o aplicativo cliente js + html ter sido inicialmente solicitado do servidor. Este "retorno de chamada" dirá ao servidor que o download do cliente foi feito com sucesso. Restrinja suas chamadas REST API para funcionar apenas se o cliente foi solicitado recentemente e com sucesso.

Agora, para usar sua API, eles devem primeiro baixar o cliente e executá-lo em um navegador. Somente depois de receber o retorno de chamada com sucesso e a entrada do usuário em um curto período de tempo, a API aceitará as chamadas.

Portanto, você não precisa se preocupar com a possibilidade de ser um usuário não autorizado sem credenciais.

(O título da pergunta, 'Como faço para proteger chamadas de API REST' e, pela maior parte do que você diz, essa é sua principal preocupação, e não a questão literal de COMO sua API é chamada, mas por QUEM, correto? )

pashute
fonte
5
O segundo ponto não faz sentido. Se um invasor precisar carregar seu aplicativo, ele o fará (seu retorno de chamada é visível). E então ataque.
Andrei Volgin
O ponto 2 é adicional ao ponto 1. O invasor ainda precisa de autenticação. O ponto 2 apenas acrescenta a necessidade de realmente baixar o aplicativo html para ser autorizado. Portanto, uma chamada direta para as APIs sem o aplicativo (presumivelmente acessada e baixada apenas após a autenticação) é impossível. Que é algo que foi solicitado nesta pergunta.
pashute
Você pode simplesmente permitir solicitações apenas do seu domínio.
Andrei Volgin
Isso apenas limita as chamadas para dentro do domínio, então agora os usuários do aplicativo de navegador javascript devem estar dentro do domínio (provavelmente não é algo que knd queria) e esses usuários ainda podem chamar a API diretamente via curl.
pashute
2
O que você parece ignorar é que o que quer que você peça ao navegador do usuário, pode ser replicado por um invasor - para que o navegador faça isso, deve ser legível.
Eugen Rieck
1
  1. Defina uma var SESSION no servidor quando o cliente carrega pela primeira vez o seu index.html(ou backbone.jsetc.)

  2. Verifique esta var no lado do servidor em cada chamada de API.

PS esta não é uma solução de "segurança" !!! Isso é apenas para facilitar a carga em seu servidor para que as pessoas não abusem dele ou "hotlink" sua API de outros sites e aplicativos.

Alex
fonte
0

Aqui está o que eu faço:

  1. Proteja a API com um cabeçalho HTTP com chamadas como X-APITOKEN:

  2. Use variáveis ​​de sessão em PHP. Tenha um sistema de login em vigor e salve o token do usuário nas variáveis ​​de sessão.

  3. Chame o código JS com Ajax para PHP e use a variável de sessão com curl para chamar a API. Dessa forma, se a variável de sessão não for definida, ela não chamará e o código PHP contém o token de acesso para a API.

Pavneet Singh
fonte