Práticas recomendadas para proteger uma API REST / serviço da web

Ao projetar uma API ou serviço REST, existem práticas recomendadas para lidar com segurança (Autenticação, Autorização, Gerenciamento de Identidade)?

Ao criar uma API SOAP, você tem o WS-Security como um guia e existe muita literatura sobre o tópico. Eu encontrei menos informações sobre como proteger endpoints REST.

Embora eu entenda que o REST intencionalmente não possui especificações análogas ao WS- *, espero que as melhores práticas ou padrões recomendados tenham surgido.

Qualquer discussão ou links para documentos relevantes seria muito apreciada. Se fosse importante, estaríamos usando o WCF com mensagens serializadas POX / JSON para nossos serviços / APIs REST criados usando v3.5 do .NET Framework.

Como tweakt disse, o Amazon S3 é um bom modelo para se trabalhar. Suas assinaturas de solicitação possuem alguns resources (como a incorporação de um registro de data e hora) que ajudam a proteger contra a reprodução acidental e mal-intencionada de solicitações.

O bom do HTTP Basic é que virtualmente todas as bibliotecas HTTP o suportam. Você precisará, é claro, exigir SSL neste caso, porque enviar senhas de texto simples pela rede é quase uma coisa ruim. Básico é preferível ao Digest ao usar o SSL porque, mesmo que o chamador já saiba que as credenciais são necessárias, o Digest exige uma viagem de ida e volta extra para trocar o valor do nonce. Com Basic, os chamadores simplesmente enviam as credenciais pela primeira vez.

Depois que a identidade do cliente é estabelecida, a autorização é realmente apenas um problema de implementação. No entanto, você pode delegar a autorização para algum outro componente com um modelo de autorização existente. Novamente, o bom sobre o Basic aqui é que o seu servidor acaba com uma cópia de texto simples da senha do cliente que você pode simplesmente passar para outro componente dentro de sua infraestrutura, conforme necessário.

Não há padrões para o REST além do HTTP. Existem serviços REST estabelecidos por aí. Eu sugiro que você dê uma olhada neles e tenha uma ideia de como eles funcionam.

Por exemplo, emprestamos muitas ideias do serviço S3 REST da Amazon ao desenvolver o nosso. Mas optamos por não usar o modelo de segurança mais avançado baseado em assinaturas de solicitação. A abordagem mais simples é a autenticação básica de HTTP sobre SSL. Você tem que decidir o que funciona melhor em sua situação.

Além disso, eu recomendo o livro RESTful Web Services da O’reilly. Ele explica os principais conceitos e fornece algumas práticas recomendadas. Geralmente, você pode pegar o modelo que ele fornece e mapeá-lo para seu próprio aplicativo.

Você também pode dar uma olhada no OAuth , um protocolo aberto emergente para autorização baseada em tokens que visa especificamente o http apis.

É muito semelhante à abordagem adotada pelo flickr e lembre-se dos “rest” apis do leite (não necessariamente bons exemplos de apis relaxantes, mas bons exemplos da abordagem baseada em tokens).

Estou surpreso com SSL com certificados de clientes que ainda não foram mencionados. De fato, essa abordagem só é realmente útil se você puder contar com a comunidade de usuários sendo identificados por certificados. Mas vários governos / empresas os emitem para seus usuários. O usuário não precisa se preocupar em criar outra combinação de nome de usuário / senha, e a identidade é estabelecida em cada conexão para que a comunicação com o servidor possa ser totalmente sem estado, sem necessidade de sessões de usuário. (Não implicar que qualquer / todas as outras soluções mencionadas requeiram sessões)

Todos nessas respostas ignoraram o verdadeiro controle de access / autorização.

Se, por exemplo, suas APIs REST / serviços da Web tratarem de POST / GET de registros médicos, você poderá definir uma política de controle de access sobre quem pode acessar os dados e sob quais circunstâncias. Por exemplo:

  • os médicos podem obter o prontuário de um paciente com quem se relacionam
  • ninguém pode publicar dados médicos fora do horário de treinamento (por exemplo, de 9 a 5)
  • os usuários finais podem obter registros médicos que possuem ou registros médicos de pacientes para quem são os guardiões
  • os enfermeiros podem ATUALIZAR o prontuário de um paciente que pertence à mesma unidade que o enfermeiro.

Para definir e implementar essas autorizações refinadas, você precisará usar uma linguagem de controle de access baseada em atributo chamada XACML, a eXtensible Access Control Markup Language.

Os outros padrões aqui são para o seguinte:

  • OAuth: id. federação e delegação de autorização, por exemplo, deixar um serviço agir em meu nome em outro serviço (o Facebook pode postar no meu Twitter)
  • SAML: federação de identidade / SSO da web. O SAML é muito sobre quem é o usuário.
  • Padrões WS-Security / WS- *: focam na comunicação entre os serviços SOAP. Eles são específicos para o formato de mensagens no nível do aplicativo (SOAP) e lidam com aspectos de mensagens, como confiabilidade, segurança, confidencialidade, integridade, atomicidade, events … Nenhum abrange o controle de access e todos são específicos do SOAP.

O XACML é independente de tecnologia. Ele pode ser aplicado a aplicativos java, .NET, Python, Ruby …, serviços da Web, APIs REST e muito mais.

A seguir estão resources interessantes:

  • o site OASIS XACML
  • o padrão NIST ABAC

Eu usei o OAuth algumas vezes e também usei alguns outros methods (BASIC / DIGEST). Eu sinceramente sugiro o OAuth. O link a seguir é o melhor tutorial que já vi sobre o uso do OAuth:

http://hueniverse.com/oauth/guide/

Existe uma ótima lista de verificação encontrada no Github :

Autenticação

  • Não reinvente a roda em Autenticação, geração de token, armazenamento de senha. Use os padrões.

  • Use os resources Max Retry e jail no Login.

  • Use criptografia em todos os dados confidenciais.

JWT (JSON Web Token)

  • Use uma chave complicada aleatória (JWT Secret) para tornar o brute forçando o token muito difícil.

  • Não extraia o algoritmo da carga útil. Force o algoritmo no backend (HS256 ou RS256).

  • Torne a expiração do token ( TTL , RTTL ) tão curta quanto possível.

  • Não armazene dados confidenciais na carga útil do JWT , pode ser facilmente decodificado.

OAuth

  • Sempre valide o redirect_uri server-side para permitir apenas URLs permitidos.

  • Sempre tente trocar por código e não tokens (não permita response_type=token ).

  • Use o parâmetro state com um hash random para evitar o CSRF no processo de autenticação do OAuth .

  • Defina o escopo padrão e valide parâmetros de escopo para cada aplicativo.

Acesso

  • Limitar solicitações (Throttling) para evitar ataques DDoS / força bruta.

  • Use HTTPS no lado do servidor para evitar MITM (Man In The Middle Attack)

  • Use o header HSTS com SSL para evitar o ataque SSL Strip.

Entrada

  • Use o método HTTP apropriado de acordo com a operação: GET (read), POST (criar), PUT/PATCH (replace / atualizar) e DELETE (para excluir um registro) e responder com 405 Method Not Allowed se o método solicitado não for é apropriado para o recurso solicitado.

  • Validar o tipo de conteúdo sob solicitação Accept header (negociação de conteúdo) para permitir apenas o formato suportado (por exemplo, application/xml , application/json , etc) e responder com 406 Not Acceptable resposta 406 Not Acceptable se não corresponder.

  • Valide o content-type de content-type dos dados postados à medida que você aceita (por exemplo, application/x-www-form-urlencoded , multipart/form-data , application/json , etc).

  • Valide a input do usuário para evitar vulnerabilidades comuns (por exemplo, XSS, SQL-Injection, Execução Remota de Código, etc).

  • Não use dados confidenciais (credenciais, senhas, tokens de segurança ou chaves de API) no URL, mas use o header de Authorization padrão.

  • Use um serviço de gateway de API para ativar as políticas de caching, Rate Limit (por exemplo, Quota, Spike Arrest, Limite de taxa simultânea) e implantar resources de APIs dinamicamente.

Em processamento

  • Verifique se todos os terminais estão protegidos por trás da autenticação para evitar o processo de autenticação interrompido.

  • O ID do recurso do próprio usuário deve ser evitado. Use / me / orders em vez de / user / 654321 / orders.

  • Não incremente os IDs. Use o UUID em vez disso.

  • Se você estiver analisando arquivos XML, certifique-se de que a análise de entidade não esteja ativada para evitar o XXE (ataque de entidade externa XML).

  • Se você estiver analisando arquivos XML, certifique-se de que a expansão da entidade não esteja ativada para evitar a bomba Billion Laughs / XML por meio do ataque de expansão de entidade exponencial.

  • Use um CDN para uploads de arquivos.

  • Se você está lidando com uma quantidade enorme de dados, use os Workers e as Filas para processar o máximo possível em segundo plano e retornar rapidamente a resposta para evitar o bloqueio de HTTP.

  • Não se esqueça de desligar o modo DEBUG .

Saída

  • Envie X-Content-Type-Options: nosniff header X-Content-Type-Options: nosniff .

  • Envie X-Frame-Options: deny header.

  • Enviar Content-Security-Policy: default-src 'none' header Content-Security-Policy: default-src 'none' .

  • Remova os headers das impressões digitais – X-Powered-By , Server , X-AspNet-Version etc.

  • Forçar o content-type para sua resposta, se você retornar application/json então seu tipo de conteúdo de resposta é application/json .

  • Não devolva dados confidenciais, como credenciais, senhas, tokens de segurança.

  • Retorne o código de status adequado de acordo com a operação concluída. (por exemplo, 200 OK , 400 Bad Request 401 Unauthorized , 401 Unauthorized , 405 Method Not Allowed , etc).

Um dos melhores posts que eu já vi em relação à segurança no que diz respeito ao REST é o 1 RainDrop . As APIs do MySpace usam o OAuth também para segurança e você tem access total aos seus canais personalizados no código RestChess, com o qual eu fiz muita exploração. Isso foi demo no Mix e você pode encontrar a postagem aqui .

Obrigado pelo excelente conselho. Acabamos usando um header HTTP personalizado para passar um token de identidade do cliente para o serviço, em preparação para integrar nossa API RESTful com a próxima estrutura do Zermatt Identity da Microsoft. Eu descrevi o problema aqui e nossa solução aqui . Eu também aceitei o conselho de Tweakt e comprei o RESTful Web Services – um ótimo livro se você está construindo uma API RESTful de qualquer tipo.

OWASP (Open Web Application Security Project) tem algumas dicas sobre todos os aspectos do desenvolvimento de aplicações web. Este projeto é uma fonte valiosa e confiável de informações. Quanto aos serviços REST, você pode verificar isso: https://www.owasp.org/index.php/REST_Security_Cheat_Sheet

Eu recomendaria o OAuth 2/3. Você pode encontrar mais informações em http://oauth.net/2/

O fato de o mundo SOAP estar bem coberto de padrões de segurança não significa que ele seja seguro por padrão. Em primeiro lugar, os padrões são muito complexos. A complexidade não é uma boa amiga das vulnerabilidades de segurança e implementação, como ataques de quebra de assinaturas XML são endêmicas aqui.

Quanto ao ambiente .NET, não ajudarei muito, mas “Construindo serviços da Web com Java” (um bloco com ~ 10 autores) ajudou-me muito a entender a arquitetura de segurança WS- * e, especialmente, suas peculiaridades.

Eu procurei muito sobre a segurança sossegada do ws e também acabamos usando o token via cookie do cliente para o servidor para autenticar as solicitações. Usei a segurança de primavera para autorização de solicitações em serviço, porque precisava autenticar e autorizar cada solicitação com base em políticas de segurança especificadas que já estavam no database.

O REST em si não oferece nenhum padrão de segurança, mas coisas como OAuth e SAML estão se tornando rapidamente os padrões nesse espaço. No entanto, autenticação e autorização são apenas uma pequena parte do que você precisa considerar. Muitas das vulnerabilidades conhecidas relacionadas aos aplicativos da Web se aplicam muito ao REST apis. Você deve considerar a validação de input, quebra de session, mensagens de erro inadequadas, vulnerabilidades internas de funcionários e assim por diante. É um assunto grande.

Eu quero adicionar (em consonância com stinkeymatt), solução mais simples seria adicionar certificados SSL ao seu site. Em outras palavras, verifique se sua URL é HTTPS: //. Isso cobrirá a segurança do seu transporte. Com a URL do RESTful, a ideia é mantê-lo simples (ao contrário do WS * security / SAML), você pode usar oAuth2 / openID connect ou até Basic Auth (em casos simples). Mas você ainda precisará de SSL / HTTPS. Por favor, verifique a segurança ASP.NET Web API 2 aqui: http://www.asp.net/web-api/overview/security (Artigos e Vídeos)

Como @Nathan acabou com o que é um simples header HTTP, e alguns disseram OAuth2 e certificados SSL do lado do cliente. A essência disso é que … sua API REST não deveria ter que lidar com segurança, já que isso deveria estar fora do escopo da API.

Em vez disso, uma camada de segurança deve ser colocada sobre ela, seja um header HTTP por trás de um proxy da Web (uma abordagem comum como o SiteMinder, Zermatt ou até mesmo o Apache HTTPd) ou tão complicado quanto o OAuth 2.

O principal é que as solicitações devem funcionar sem qualquer interação com o usuário final. Tudo o que é necessário é garantir que a conexão com a API REST seja autenticada. No Java EE, temos a noção de um userPrincipal que pode ser obtido em um HttpServletRequest . Também é gerenciado no descritor de implementação que um padrão de URL pode ser seguro, portanto, o código da API REST não precisa mais verificar.

No mundo do WCF, eu usaria ServiceSecurityContext.Current para obter o contexto de segurança atual. Você precisa configurar seu aplicativo para exigir autenticação.

Há uma exceção para a declaração que eu tinha acima e que é o uso de um nonce para evitar replays (que podem ser ataques ou alguém apenas enviando os mesmos dados duas vezes). Essa parte só pode ser tratada na camada de aplicativo.

Para a Segurança de Aplicações Web, você deve dar uma olhada no OWASP ( https://www.owasp.org/index.php/Main_Page ), que fornece cheatsheets para vários ataques de segurança. Você pode incorporar tantas medidas quanto possível para proteger seu aplicativo. Com relação à segurança da API (autorização, autenticação, gerenciamento de identidades), existem várias maneiras, como já mencionamos (Basic, Digest e OAuth). Há buracos no OAuth1.0, portanto, você pode usar o OAuth1.0a (o OAuth2.0 não é amplamente adotado devido a preocupações com a especificação)

Já faz um tempo, mas a questão ainda é relevante, embora a resposta possa ter mudado um pouco.

Um gateway de API seria uma solução flexível e altamente configurável. Eu testei e usei bastante o KONG e realmente gostei do que vi. O KONG fornece uma API REST de administração própria que você pode usar para gerenciar usuários.

O Express-gateway.io é mais recente e também é um gateway de API.