Estou desenvolvendo uma API REST que requer autenticação. Como a autenticação em si ocorre por meio de um serviço da web externo por HTTP, concluí que distribuiríamos tokens para evitar chamar repetidamente o serviço de autenticação. O que me leva perfeitamente à minha primeira pergunta:
Isso é realmente melhor do que apenas exigir que os clientes usem a autenticação básica HTTP em cada solicitação e fazer chamadas em cache para o serviço de autenticação do lado do servidor?
A solução de autenticação básica tem a vantagem de não exigir uma ida e volta completa ao servidor antes que as solicitações de conteúdo possam começar. Os tokens podem ser potencialmente mais flexíveis no escopo (por exemplo, conceder direitos a recursos ou ações específicos), mas isso parece mais apropriado ao contexto OAuth do que no meu caso de uso mais simples.
Atualmente, os tokens são adquiridos assim:
curl -X POST localhost/token --data "api_key=81169d80...
&verifier=2f5ae51a...
×tamp=1234567
&user=foo
&pass=bar"
O api_key
, timestamp
e verifier
são exigidos por todas as solicitações. O "verificador" é retornado por:
sha1(timestamp + api_key + shared_secret)
Minha intenção é permitir apenas chamadas de partes conhecidas e impedir que as chamadas sejam reutilizadas literalmente.
Isso é bom o suficiente? Underkill? Exagero?
Com um token em mãos, os clientes podem adquirir recursos:
curl localhost/posts?api_key=81169d80...
&verifier=81169d80...
&token=9fUyas64...
×tamp=1234567
Para a ligação mais simples possível, isso parece horrivelmente detalhado. Considerando que a shared_secret
vontade acabará sendo incorporada (no mínimo) a um aplicativo iOS, do qual eu assumiria que pode ser extraído, isso oferece algo além de uma falsa sensação de segurança?
fonte
Respostas:
Deixe-me separar tudo e resolver abordar cada problema isoladamente:
Autenticação
Para autenticação, o baseauth tem a vantagem de ser uma solução madura no nível do protocolo. Isso significa que muitos problemas "podem surgir mais tarde" já estão resolvidos para você. Por exemplo, com BaseAuth, os agentes do usuário sabem que a senha é uma senha e, portanto, não a armazenam em cache.
Carregamento do servidor de autenticação
Se você distribuir um token para o usuário em vez de armazenar em cache a autenticação no servidor, continuará fazendo o mesmo: Armazenando em cache as informações de autenticação. A única diferença é que você está transferindo a responsabilidade pelo armazenamento em cache para o usuário. Isso parece uma mão-de-obra desnecessária para o usuário sem ganhos, por isso recomendo lidar com isso de forma transparente no servidor, conforme sugerido.
Segurança de transmissão
Se você pode usar uma conexão SSL, isso é tudo, a conexão é segura *. Para impedir a execução múltipla acidental, você pode filtrar vários URLs ou solicitar aos usuários que incluam um componente aleatório ("nonce") no URL.
Se isso não for possível e as informações transmitidas não forem secretas, recomendo proteger a solicitação com um hash, conforme sugerido na abordagem de token. Como o hash fornece a segurança, você pode instruir seus usuários a fornecer o hash como a senha básica. Para maior robustez, recomendo o uso de uma sequência aleatória em vez do registro de data e hora como um "nonce" para impedir ataques de repetição (duas solicitações legítimas podem ser feitas durante o mesmo segundo). Em vez de fornecer campos separados "segredo compartilhado" e "chave da API", você pode simplesmente usar a chave da API como segredo compartilhado e, em seguida, usar um sal que não seja alterado para impedir ataques à tabela do arco-íris. O campo de nome de usuário também parece um bom lugar para colocar o nonce, pois faz parte da autenticação. Então agora você tem uma chamada limpa como esta:
É verdade que isso é um pouco trabalhoso. Isso ocorre porque você não está usando uma solução em nível de protocolo (como SSL). Portanto, pode ser uma boa ideia fornecer algum tipo de SDK aos usuários, para que pelo menos eles não precisem passar por eles mesmos. Se você precisar fazer dessa maneira, acho o nível de segurança adequado (kill com o botão direito).
Armazenamento secreto seguro
Depende de quem você está tentando impedir. Se você estiver impedindo que pessoas com acesso ao telefone do usuário usem o serviço REST no nome do usuário, seria uma boa ideia encontrar algum tipo de API de chaveiro no sistema operacional de destino e fazer com que o SDK (ou o implementador) armazene o chave lá. Se isso não for possível, você pode pelo menos tornar um pouco mais difícil obter o segredo, criptografando-o e armazenando os dados criptografados e a chave de criptografia em locais separados.
Se você está tentando impedir que outros fornecedores de software obtenham sua chave de API para impedir o desenvolvimento de clientes alternativos, apenas a abordagem de criptografar e armazenar separadamente quase funciona. Essa é uma criptografia de caixa branca e, até o momento, ninguém apresentou uma solução verdadeiramente segura para os problemas dessa classe. O mínimo que você pode fazer é emitir uma única chave para cada usuário, para que você possa banir as chaves abusadas.
(*) EDIT: As conexões SSL não devem mais ser consideradas seguras sem a adoção de etapas adicionais para verificá- las.
fonte
Uma API RESTful pura deve usar os recursos padrão do protocolo subjacente:
Para HTTP, a API RESTful deve estar em conformidade com os cabeçalhos padrão HTTP existentes. A adição de um novo cabeçalho HTTP viola os princípios REST. Não reinvente a roda, use todos os recursos padrão nos padrões HTTP / 1.1 - incluindo códigos de resposta de status, cabeçalhos etc. Os serviços da Web RESTFul devem aproveitar e confiar nos padrões HTTP.
Os serviços RESTful DEVEM SER INTELIGENTES. Quaisquer truques, como autenticação baseada em token, que tenta lembrar o estado das solicitações REST anteriores no servidor, violam os princípios REST. Novamente, isso é uma obrigação; ou seja, se o servidor da web salvar qualquer informação relacionada ao contexto de solicitação / resposta no servidor na tentativa de estabelecer qualquer tipo de sessão no servidor, seu serviço da web NÃO será Stateless. E se NÃO é apátrida, NÃO é RESTFul.
Conclusão: para fins de autenticação / autorização, você deve usar o cabeçalho de autorização padrão HTTP. Ou seja, você deve adicionar o cabeçalho de autorização / autenticação HTTP em cada solicitação subsequente que precisar ser autenticada. A API REST deve seguir os padrões do esquema de autenticação HTTP. As especificações de como esse cabeçalho deve ser formatado são definidas nos padrões HTTP 1.1 da RFC 2616 - seção 14.8 Autorização da RFC 2616 e na autenticação HTTP da RFC 2617: autenticação de acesso básico e digest .
Eu desenvolvi um serviço RESTful para o aplicativo Cisco Prime Performance Manager. Pesquise no Google o documento da API REST que escrevi para esse aplicativo para obter mais detalhes sobre a conformidade da API RESTFul aqui . Nessa implementação, eu escolhi usar o esquema de autorização "Básico" HTTP. - verifique a versão 1.5 ou superior desse documento da API REST e procure autorização no documento.
fonte
Na web, um protocolo stateful baseia-se em ter um token temporário que é trocado entre um navegador e um servidor (via cabeçalho de cookie ou reescrita de URI) em cada solicitação. Esse token geralmente é criado na extremidade do servidor e é um dado opaco que tem um certo tempo de vida útil e tem o único objetivo de identificar um agente de usuário da web específico. Ou seja, o token é temporário e se torna um ESTADO que o servidor da web deve manter em nome de um agente de usuário do cliente durante a duração dessa conversa. Portanto, a comunicação usando um token dessa maneira é STATEFUL. E se a conversa entre cliente e servidor for STATEFUL, não será RESTful.
O nome de usuário / senha (enviado no cabeçalho da Autorização) geralmente é mantido no banco de dados com a intenção de identificar um usuário. Às vezes, o usuário pode significar outro aplicativo; no entanto, o nome de usuário / senha NUNCA se destina a identificar um agente de usuário cliente Web específico. A conversa entre um agente e servidor da Web com base no uso do nome de usuário / senha no cabeçalho da Autorização (após a Autorização Básica HTTP) é STATELESS porque o front-end do servidor da Web não está criando ou mantendo nenhuma informação STATEqualquer que seja em nome de um agente de usuário do cliente da Web específico. E, com base no meu entendimento do REST, o protocolo declara claramente que a conversa entre clientes e servidor deve ser INTELIGENTE. Portanto, se quisermos ter um serviço RESTful verdadeiro, devemos usar nome de usuário / senha (consulte a RFC mencionada na minha postagem anterior) no cabeçalho da autorização para cada chamada única, NÃO um tipo de token de sensação (por exemplo, tokens de sessão criados em servidores da web) , Tokens OAuth criados em servidores de autorização e assim por diante).
Entendo que vários provedores REST chamados estão usando tokens como OAuth1 ou OAuth2 accept-tokens a serem passados como "Autorização: Portadora" nos cabeçalhos HTTP. No entanto, parece-me que o uso desses tokens para serviços RESTful violaria o verdadeiro significado de STATELESS que o REST adota; porque esses tokens são dados temporários criados / mantidos no lado do servidor para identificar um agente de usuário do cliente da web específico pela duração válida de uma conversa desse cliente da web / servidor. Portanto, qualquer serviço que esteja usando esses tokens OAuth1 / 2 não deve ser chamado de REST se quisermos manter o significado VERDADEIRO de um protocolo STATELESS.
Rubens
fonte