Autenticação RESTful


745

O que significa a autenticação RESTful e como funciona? Não consigo encontrar uma boa visão geral no Google. Meu único entendimento é que você passa a chave da sessão (remeberal) na URL, mas isso pode estar terrivelmente errado.


3
Quando pesquiso no Google Restful Authentication, encontro uma dúzia de plugins RoR. Eu estou supondo que aqueles NÃO são o que você está procurando. Se não o RoR, então qual idioma? Qual servidor web?
26568 S.Lott

2
Não será terrivelmente errado se você usar HTTPS. A solicitação HTTP completa, juntamente com a URL, seria criptografada.
Bharat Khatri

4
@BharatKhatri: Sim, seria. Eu nunca passaria informações confidenciais no URL visível para o usuário. É muito provável que essas informações vazem para fins práticos. O HTTPS não pode ajudar em caso de vazamento acidental.
Jo Então,

2
@jcoffland: O que você quer dizer com autenticação RESTful real? Estou interessado porque acabei de implementar a terceira maneira a partir da resposta aceita, no entanto, não estou feliz com isso (não gosto dos parâmetros adicionais no URL).
BlueLettuce16

4
algumas pessoas usam jwt.io/introduction para resolver isso. Eu pesquiso sobre isso agora para resolver meu caso: stackoverflow.com/questions/36974163/… >> Espero que isso funcione bem.
toha

Respostas:


586

Como lidar com a autenticação em uma arquitetura RESTful Client-Server é uma questão de debate.

Geralmente, isso pode ser alcançado no mundo SOA sobre HTTP via:

  • Autenticação básica HTTP sobre HTTPS;
  • Gerenciamento de cookies e sessões;
  • Token em cabeçalhos HTTP (por exemplo, OAuth 2.0 + JWT);
  • Autenticação de consulta com parâmetros de assinatura adicionais.

Você terá que se adaptar, ou ainda melhor, misturar essas técnicas, para combinar com sua arquitetura de software, na melhor das hipóteses.

Cada esquema de autenticação possui seus próprios PROs e CONs, dependendo do objetivo da sua política de segurança e arquitetura de software.

Autenticação básica HTTP sobre HTTPS

Essa primeira solução, baseada no protocolo HTTPS padrão, é usada pela maioria dos serviços web.

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

É fácil de implementar, disponível por padrão em todos os navegadores, mas possui algumas desvantagens conhecidas, como a terrível janela de autenticação exibida no Navegador, que persiste (não há recurso semelhante ao LogOut aqui), algum consumo adicional de CPU no servidor, e o fato de o nome de usuário e a senha serem transmitidos (via HTTPS) para o servidor (deve ser mais seguro permitir que a senha permaneça apenas no lado do cliente, durante a entrada do teclado e seja armazenada como hash seguro no servidor) .

Podemos usar a autenticação Digest , mas também requer HTTPS, pois é vulnerável a ataques MiM ou Replay e é específico para HTTP.

Sessão via Cookies

Para ser sincero, uma sessão gerenciada no servidor não é verdadeiramente sem estado.

Uma possibilidade poderia ser manter todos os dados no conteúdo do cookie. E, por padrão, o cookie é manipulado no lado do servidor (o cliente, na verdade, nem tenta interpretar esses dados do cookie: apenas o devolve ao servidor a cada solicitação sucessiva). Mas esses dados do cookie são dados do estado do aplicativo, portanto, o cliente deve gerenciá-los, não o servidor, em um mundo sem Estado puro.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

A técnica do cookie em si é vinculada ao HTTP, portanto, não é verdadeiramente RESTful, que deve ser independente do protocolo, IMHO. É vulnerável a ataques MiM ou Replay .

Concedido por token (OAuth2)

Uma alternativa é colocar um token nos cabeçalhos HTTP para que a solicitação seja autenticada. É isso que o OAuth 2.0 faz, por exemplo. Veja o RFC 6749 :

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

Em resumo, isso é muito semelhante a um cookie e sofre os mesmos problemas: não estático, depende de detalhes de transmissão HTTP e está sujeito a muitas deficiências de segurança - incluindo MiM e Replay -, portanto, deve ser usado apenas por HTTPS. Normalmente, um JWT é usado como um token.

Autenticação de consulta

A autenticação de consulta consiste em assinar cada solicitação RESTful por meio de alguns parâmetros adicionais no URI. Veja este artigo de referência .

Foi definido como tal neste artigo:

Todas as consultas REST devem ser autenticadas assinando os parâmetros de consulta classificados em ordem alfabética minúscula, usando a credencial privada como o token de assinatura. A assinatura deve ocorrer antes do URL que codifica a string de consulta.

Essa técnica é talvez a mais compatível com uma arquitetura Stateless e também pode ser implementada com um gerenciamento de sessões simples (usando sessões na memória em vez de persistência de banco de dados).

Por exemplo, aqui está uma amostra de URI genérica no link acima:

GET /object?apiKey=Qwerty2010

deve ser transmitido como tal:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

A cadeia de caracteres assinada é /object?apikey=Qwerty2010&timestamp=1261496500e a assinatura é o hash SHA256 dessa cadeia de caracteres usando o componente privado da chave da API.

O cache de dados do servidor pode estar sempre disponível. Por exemplo, em nossa estrutura, armazenamos em cache as respostas no nível SQL, não no URI. Portanto, adicionar esse parâmetro extra não quebra o mecanismo de cache.

Consulte este artigo para obter alguns detalhes sobre autenticação RESTful em nossa estrutura ORM / SOA / MVC cliente-servidor, com base em JSON e REST. Como permitimos a comunicação não apenas por HTTP / 1.1, mas também por pipes nomeados ou mensagens GDI (localmente), tentamos implementar um padrão de autenticação verdadeiramente RESTful e não dependemos da especificidade do HTTP (como cabeçalho ou cookies).

Nota posterior : adicionar uma assinatura ao URI pode ser considerado uma má prática (uma vez que, por exemplo, aparecerá nos logs do servidor http), pelo que deve ser mitigado, por exemplo, por um TTL adequado para evitar replays. Mas se seus logs http estiverem comprometidos, você certamente terá maiores problemas de segurança.

Na prática, a próxima autenticação de token MAC para OAuth 2.0 pode ser uma grande melhoria em relação ao esquema atual "Granted by Token". Mas este ainda é um trabalho em andamento e está vinculado à transmissão HTTP.

Conclusão

Vale a pena concluir que o REST não é apenas baseado em HTTP, mesmo que, na prática, ele também seja implementado principalmente por HTTP. O REST pode usar outras camadas de comunicação. Portanto, uma autenticação RESTful não é apenas sinônimo de autenticação HTTP, independentemente do que o Google responder. Ele nem deve usar o mecanismo HTTP, mas deve ser abstraído da camada de comunicação. E se você usar a comunicação HTTP, graças à iniciativa Let's Encrypt, não há razão para não usar HTTPS adequado, necessário além de qualquer esquema de autenticação.


5
Se você usar Cookiecomo um substituto melhor, HTTP Basic Authpoderá fazer uma autenticação verdadeiramente sem estado com um método para expirar a autenticação e a capacidade de sair. Um exemplo de implementação pode usar o cookie chamado Emulated-HTTP-Basic-Authcom valor semelhante ao HTTP Basic Auth real e, além disso, definir o tempo de expiração. O logout pode ser implementado com a remoção desse cookie. Eu acho que qualquer cliente capaz de oferecer suporte a autenticação básica HTTP também pode suportar autenticação de cookies feita dessa maneira.
Mikko Rantalainen

4
@MikkoRantalainen Mas esse cookie ainda será gerenciado pelo servidor, como escrevi. É algum tipo de apátrida, mas não apátrida "pura". Em todos os casos, você precisa de um código JavaScript dedicado ao logon / logout do cliente, o que é perfeitamente possível, por exemplo, com HTTP Digest Auth - boa ideia, mas não há grande benefício, aqui, de reinventar a roda.
Arnaud Bouchez

4
Eu diria que o servidor implementa a interface do usuário e a lógica para configurar o cabeçalho, mas o próprio cabeçalho é sem estado. Um cliente projetado para a API pode pular usando a ajuda do servidor para configurar o cabeçalho e apenas passar as informações necessárias semelhantes ao HTTP Basic Auth. O que quero dizer é que os UAs comuns (navegadores) têm uma implementação tão ruim do Basic Auth que não podem ser usados. Um servidor fornecido emulação para o mesmo material em outro cabeçalho ( Cookie) pode ser usado.
Mikko Rantalainen

6
Eu acho que a resposta correta é stackoverflow.com/questions/6068113/…
graffic

7
O prompt de senha feia para autorização HTTP será exibido apenas se o servidor solicitar, enviando de volta a resposta 401 Não autorizada. Se você não gostar, basta enviar um 403 Proibido. A página de erro pode incluir um método para fazer login ou um link para ela. No entanto, o maior argumento contra os cookies E a autenticação http (independentemente de o estado ser do lado do servidor ou do cliente) é que eles são vulneráveis ​​à falsificação de solicitações entre sites. Por esse motivo, a melhor abordagem é um esquema de autorização personalizado, cabeçalho de autorização personalizado ou parâmetro personalizado GET ou POST.
Dobes Vandermeer

418

Duvido que as pessoas que gritavam com entusiasmo "Autenticação HTTP" alguma vez tentaram criar um aplicativo baseado em navegador (em vez de um serviço da web máquina a máquina) com REST (sem ofensas - apenas acho que nunca enfrentaram as complicações) .

Os problemas encontrados ao usar a autenticação HTTP nos serviços RESTful que produzem páginas HTML para serem exibidas em um navegador são:

  • o usuário normalmente recebe uma caixa de login feia feita pelo navegador, que é muito hostil ao usuário. você não pode adicionar recuperação de senha, caixas de ajuda, etc.
  • sair ou fazer login com um nome diferente é um problema - os navegadores continuarão enviando informações de autenticação para o site até você fechar a janela
  • timeouts são difíceis

Um artigo muito perspicaz que aborda esses pontos por ponto está aqui , mas isso resulta em uma muitos hackers de javascript específicos do navegador, soluções alternativas para soluções alternativas, etc. Como tal, também não é compatível com o futuro, portanto, será necessária manutenção constante à medida que novos navegadores forem lançados. Eu não considero esse design limpo e claro, além de sentir que é muito trabalho extra e dor de cabeça, para que eu possa mostrar com entusiasmo meu distintivo REST aos meus amigos.

Eu acredito que os cookies são a solução. Mas espere, biscoitos são maus, não são? Não, não são, a maneira como os cookies são frequentemente usados ​​é ruim. Um cookie em si é apenas uma informação do lado do cliente, assim como as informações de autenticação HTTP que o navegador acompanharia enquanto você navega. E essas informações do lado do cliente são enviadas ao servidor a cada solicitação, novamente como as informações de autenticação HTTP. Conceitualmente, a única diferença é que o conteúdo dessa parte do estado do lado do cliente pode ser determinado pelo servidor como parte de sua resposta.

Tornando as sessões um recurso RESTful com apenas as seguintes regras:

  • Uma sessão mapeia uma chave para um ID do usuário (e possivelmente um último carimbo de data / hora da ação para tempos limite)
  • Se uma sessão existir , isso significa que a chave é válida.
  • Login significa POSTing para / sessions, uma nova chave é definida como um cookie
  • Logout significa DELETEing / sessions / {key} (com o POST sobrecarregado, lembre-se, somos um navegador e o HTML 5 ainda é um longo caminho a percorrer)
  • A autenticação é feita enviando a chave como um cookie a cada solicitação e verificando se a sessão existe e é válida

A única diferença para a autenticação HTTP, agora, é que a chave de autenticação é gerada pelo servidor e enviada ao cliente que continua enviando de volta, em vez de o cliente computá-la a partir das credenciais inseridas.

converter42 acrescenta que, ao usar https (o que deveríamos), é importante que o cookie tenha seu sinalizador seguro definido para que as informações de autenticação nunca sejam enviadas por uma conexão não segura. Ótimo ponto, eu não tinha visto.

Sinto que esta é uma solução suficiente que funciona bem, mas devo admitir que não sou especialista em segurança o suficiente para identificar possíveis falhas nesse esquema - tudo o que sei é que centenas de aplicativos da Web não RESTful usam essencialmente o mesmo protocolo de login ($ _SESSION em PHP, HttpSession em Java EE, etc.). O conteúdo do cabeçalho do cookie é simplesmente usado para endereçar um recurso do lado do servidor, assim como um idioma de aceitação pode ser usado para acessar recursos de tradução, etc. Eu sinto que é o mesmo, mas talvez outros não? O que vocês acham pessoal?


68
Esta é uma resposta pragmática e a solução proposta funciona. No entanto, o uso dos termos "RESTful" e "session" na mesma frase está errado (a menos que também não haja "not" no meio;). Em outras palavras: qualquer serviço da Web que use sessões NÃO é RESTful (por definição). Não me interpretem mal - você ainda pode usar esta solução (YMMV), mas o termo "RESTful" não pode ser usado para isso. Eu recomendo o livro O'Reilly sobre REST, que é muito legível e explica o assunto em profundidade.
Johndodo 29/07

23
@skrebbel: a solução REST pura envia dados de autenticação cada vez que solicita um recurso, o que é menos que perfeito (o HTTP Auth faz isso). A solução proposta funciona e é melhor para a maioria dos casos de uso, mas não é RESTful. Não há necessidade de guerra, eu também uso esta solução. Eu apenas não afirmo que é RESTful. :)
johndodo

94
Oh, vamos lá, dê um exemplo então. Qual é a outra maneira, que funciona bem? Eu realmente gostaria de saber. A autenticação HTTP certamente não é, você não pode fazer o logout sem fechar o navegador e não pode oferecer UX de login decente sem muitas JS não compatíveis com o futuro, específicas do navegador. Não me importo muito com "puramente RESTful" vs "quase RESTful" e com todo o debate religioso associado, mas se você disser que existem várias maneiras, você deve explicá-las.
skrebbel

15
Uma autenticação verdadeiramente RESTful com agentes de usuários do mundo real (também conhecidos como "navegadores") consiste em um cookie que contém o valor da autenticação HTTP. Dessa forma, o servidor pode fornecer a interface do usuário para inserir login e senha e o servidor pode forçar o logout (excluindo o cookie). Além disso, em vez de responder ao 401 para exigir login quando a autenticação falhar, o servidor deve usar o redirecionamento temporário para a tela de login e, após o login bem-sucedido, usar o redirecionamento temporário para o local anterior. Além disso, o servidor deve incorporar a ação de logout (formulário POST) a praticamente todas as páginas dos usuários logados.
Mikko Rantalainen

15
Não vejo nada de errado em usar "restful" e "session" na mesma frase, desde que fique claro que a sessão existe apenas no lado do cliente. Não sei por que é feito um grande negócio sobre esse conceito.
21412 Joe Phillips

140

Já chega de falar sobre esse assunto por gente boa aqui. Mas aqui estão meus 2 centavos.

Existem 2 modos de interação:

  1. homem-para-máquina (HTM)
  2. máquina a máquina (MTM)

A máquina é o denominador comum, expresso como APIs REST, e os atores / clientes são os humanos ou as máquinas.

Agora, em uma arquitetura verdadeiramente RESTful, o conceito de apatridia implica que todos os estados de aplicativos relevantes (ou seja, os estados do lado do cliente) devem ser fornecidos com cada solicitação. Por relevante, significa que tudo o que é exigido pela API REST para processar a solicitação e fornecer uma resposta apropriada.

Quando consideramos isso no contexto de aplicativos humano-para-máquina, "com base no navegador", como o Skrebbel aponta acima, isso significa que o aplicativo (web) em execução no navegador precisará enviar seu estado e informações relevantes a cada solicitação cria para as APIs REST de back-end.

Considere o seguinte: Você tem um ativo exposto na plataforma de dados / informações de APIs REST. Talvez você tenha uma plataforma de BI de autoatendimento que lida com todos os cubos de dados. Mas você deseja que seus clientes (humanos) acessem esse recurso via (1) aplicativo Web, (2) aplicativo móvel e (3) algum aplicativo de terceiros. No final, uma cadeia uniforme de MTMs leva ao HTM - certo. Portanto, os usuários humanos permanecem no ápice da cadeia de informações.

Nos 2 primeiros casos, você tem um caso de interação homem-máquina, as informações sendo realmente consumidas por um usuário humano. No último caso, você tem um programa de máquina consumindo as APIs REST.

O conceito de autenticação se aplica de maneira geral. Como você projetará isso para que suas APIs REST sejam acessadas de maneira uniforme e segura? Do jeito que eu vejo isso, existem 2 maneiras:

Maneira-1:

  1. Não há login, para começar. Toda solicitação realiza o login
  2. O cliente envia seus parâmetros de identificação + os parâmetros específicos da solicitação a cada solicitação
  3. A API REST pega, vira, pinga no repositório de usuários (o que quer que seja) e confirma a autenticação
  4. Se a autenticação é estabelecida, atende à solicitação; caso contrário, nega com o código de status HTTP apropriado
  5. Repita o procedimento acima para todas as solicitações em todas as APIs REST do seu catálogo

Caminho-2:

  1. O cliente começa com uma solicitação de autenticação
  2. Uma API REST de login manipulará todos esses pedidos
  3. Ele pega os parâmetros de autenticação (chave API, uid / pwd ou o que você escolher) e verifica a autenticação no repositório de usuários (LDAP, AD ou MySQL DB etc.)
  4. Se verificado, cria um token de autenticação e o devolve ao cliente / chamador
  5. O chamador então envia esse token de autenticação + solicitação de parâmetros específicos com cada solicitação subsequente para outras APIs REST de negócios, até que seja desconectado ou até que a concessão expire

Claramente, no Modo 2, as APIs REST precisarão de uma maneira de reconhecer e confiar no token como válido. A API de logon executou a verificação de autenticação e, portanto, essa "chave com manobrista" precisa ser confiável por outras APIs REST em seu catálogo.

Obviamente, isso significa que a chave / token de autenticação precisará ser armazenada e compartilhada entre as APIs REST. Esse repositório de token confiável e compartilhado pode ser local / federado, o que permite, permitindo que APIs REST de outras organizações confiem uma na outra.

Mas eu discordo.

O ponto é que um "estado" (sobre o status autenticado do cliente) precisa ser mantido e compartilhado para que todas as APIs REST possam criar um círculo de confiança. Se não fizermos isso, que é o Caminho-1, devemos aceitar que um ato de autenticação deve ser realizado para qualquer / todas as solicitações que chegarem.

Executar autenticação é um processo que consome muitos recursos. Imagine executar consultas SQL, para cada solicitação recebida, no seu repositório de usuários para verificar a correspondência de uid / pwd. Ou, para criptografar e executar correspondências de hash (o estilo da AWS). E, arquitetonicamente, todas as APIs REST precisarão executar isso, suspeito, usando um serviço de login de back-end comum. Porque, se não o fizer, você distribui o código de autenticação em todos os lugares. Uma grande bagunça.

Mais camadas, mais latência.

Agora, pegue o Caminho 1 e aplique ao HTM. O seu usuário (humano) realmente se importa se você precisa enviar uid / pwd / hash ou qualquer outra coisa a cada solicitação? Não, contanto que você não a incomode jogando a página de autenticação / login a cada segundo. Boa sorte em ter clientes, se você tiver. Então, o que você fará é armazenar as informações de login em algum lugar do lado do cliente, no navegador, logo no início e enviá-las com todas as solicitações feitas. Para o usuário (humano), ele já fez login e uma "sessão" está disponível. Mas, na realidade, ela é autenticada em todos os pedidos.

Mesmo com a maneira 2. Seu usuário (humano) nunca notará. Portanto, nenhum dano foi feito.

E se aplicarmos o Caminho 1 ao MTM? Nesse caso, como é uma máquina, podemos aborrecer esse cara pedindo que ele envie informações de autenticação a cada solicitação. Ninguém se importa! Executar o Way-2 no MTM não evocará nenhuma reação especial; é uma máquina maldita. Poderia se importar menos!

Então, realmente, a questão é o que se adequa às suas necessidades. Apatridia tem um preço a pagar. Pague o preço e siga em frente. Se você quer ser um purista, pague o preço também e siga em frente.

No final, filosofias não importam. O que realmente importa é a descoberta de informações, a apresentação e a experiência de consumo. Se as pessoas amam suas APIs, você fez seu trabalho.


3
Senhor, você explicou isso tão lindamente que tenho uma idéia clara da questão / questão básica em mãos. Você é como o Buda! Posso acrescentar que usando HTTPS na camada de transporte, podemos até mesmo impedir homem no meio ataques, de modo que ninguém rouba o meu identificador de chave (se Way-1 é escolhida)
Vishnoo Rath

Não é sempre uma máquina que faz a autenticação? O humano não dá a mínima para as senhas, é um aborrecimento infeliz para os usuários que racionalizam corretamente a segurança. Para mim, é um problema do desenvolvedor como eles querem que a máquina faça seu trabalho.
Todd Baur

9
Eu li sua resposta; em sua solução, para cada solicitação da Web originada no navegador por cliques do usuário, será necessário enviar o "token de autenticação" para qualquer API que o usuário estiver chamando. O que então? A API executa a verificação no token. Contra o que? Contra algum tipo de "armazenamento de token" que mantém se esse token é válido ou não. Você não concorda que esse "armazenamento de tokens" se torna o guardião do "estado"? Realmente, da maneira que você vê isso, alguém em algum lugar precisa saber algo sobre os "tokens" transmitidos nas atividades do usuário. É onde mora a informação do estado.
Kingz

5
E por serviço "sem estado", o que realmente significa é que esse componente específico do servidor (as APIs CRUD) não possui nenhum estado. Eles não reconhecem um usuário de outro e concluem a solicitação do usuário em sua totalidade em uma transação. Isso é apatridia. Mas alguém em algum lugar deve estar sentado e julgando se esse usuário é válido ou não. Não há outra maneira de fazer isso; chaves ou senhas ou qualquer outra coisa. Qualquer coisa passada pelo lado do usuário deve ser autenticada e autorizada.
Kingz

1
Você está ausente Way-3, a abordagem híbrida. O cliente efetua login como em Way-2, mas, como em Way-1, as credenciais não são verificadas em nenhum estado do lado do servidor. Independentemente disso, um token de autenticação é criado e enviado de volta ao cliente como em Way-2. Mais tarde, esse token é verificado quanto à autenticidade usando criptografia assimétrica, sem procurar qualquer estado específico do cliente.
Jcoffland # 7/15

50

Aqui está uma solução de autenticação RESTful verdadeira e completamente:

  1. Crie um par de chaves pública / privada no servidor de autenticação.
  2. Distribua a chave pública para todos os servidores.
  3. Quando um cliente se autentica:

    3.1 emita um token que contém o seguinte:

    • Data de validade
    • nome de usuário (opcional)
    • IP de usuários (opcional)
    • hash de uma senha (opcional)

    3.2 Criptografe o token com a chave privada.

    3.3 Envie o token criptografado de volta ao usuário.

  4. Quando o usuário acessa qualquer API, ele também deve passar seu token de autenticação.

  5. Os servidores podem verificar se o token é válido descriptografando-o usando a chave pública do servidor de autenticação.

Esta é uma autenticação sem estado / RESTful.

Observe que, se um hash de senha fosse incluído, o usuário também enviaria a senha não criptografada junto com o token de autenticação. O servidor pôde verificar se a senha correspondia à senha usada para criar o token de autenticação comparando hashes. Uma conexão segura usando algo como HTTPS seria necessária. O Javascript no lado do cliente pode lidar com a obtenção da senha do usuário e o armazenamento no lado do cliente, na memória ou em um cookie, possivelmente criptografado com a chave pública do servidor .


5
E se alguém se apossar desse token de autenticação e invocar APIs com ele fingindo ser cliente?
Abidi 23/10/2013

2
@ Abidi, sim, isso é um problema. Você pode exigir uma senha. Um hash da senha pode ser incluído no token de autenticação. Se alguém pudesse roubar o token, seria vulnerável a ataques de força bruta offline. Se uma senha forte fosse escolhida, isso não seria um problema. Observe que, se você usasse o roubo de tokens https, o invasor obteria primeiro acesso à máquina do cliente.
Jcoffland

1
Porque apenas o servidor de autenticação conhece a chave privada. Outros servidores podem autenticar o usuário sabendo apenas a chave pública e o token do usuário.
precisa saber é o seguinte

1
A criptografia e descriptografia assimétrica são uma ordem de magnitude mais lenta (mais intensivas em computação) do que a criptografia simétrica. Ter o servidor usando a chave pública para descriptografar o token em todas as chamadas seria um enorme gargalo de desempenho.
Craig

3
@jcoffland, você realmente promoveu sua resposta aqui (repetidamente :-) Mas não posso deixar de comentar sobre os problemas de desempenho (intensidade de computação) do uso de criptografia assimétrica em todas as chamadas. Eu simplesmente não consigo ver uma solução que faça isso com qualquer capacidade de escalar. Procure HTTPS e o protocolo SPDY. Ele faz todo o possível para manter as conexões abertas (keep-alives HTTP, que é o estado) e serve vários recursos em lotes na mesma conexão (mais estado), e, é claro, o próprio SSL usa apenas criptografia assimétrica para trocar uma chave de cifra simétrica ( também estado).
Craig

37

Para ser honesto com você, já vi ótimas respostas aqui, mas algo que me incomoda um pouco é quando alguém leva todo o conceito de Stateless ao extremo, onde se torna dogmático. Isso me lembra aqueles velhos fãs do Smalltalk que queriam apenas adotar OO puro e se algo não é um objeto, então você está fazendo errado. Me dá um tempo.

A abordagem RESTful deve facilitar sua vida e reduzir a sobrecarga e o custo das sessões, tente segui-la da maneira mais sábia, mas no minuto em que você seguir uma disciplina (qualquer disciplina / orientação) ao extremo onde não fornece mais o benefício a que se destinava, então você está fazendo errado. Atualmente, algumas das melhores linguagens possuem programação funcional e orientação a objetos.

Se a maneira mais fácil de resolver seu problema é armazenar a chave de autenticação em um cookie e enviá-la no cabeçalho HTTP, faça-o, apenas não abuse. Lembre-se de que as sessões são ruins quando se tornam pesadas e grandes, se toda a sua sessão consiste em uma sequência curta contendo uma chave, então qual é o problema?

Estou aberto a aceitar correções nos comentários, mas simplesmente não vejo sentido (até agora) em tornar nossas vidas miseráveis ​​para simplesmente evitar manter um grande dicionário de hashes em nosso servidor.


2
As pessoas não estão tentando proibi-lo de usar sessões. Você é livre para fazê-lo. Mas se você fizer, não é REST.
André Caldas

6
@ AndréCaldas, não é REST da mesma maneira que ter funções ou tipos primitivos em um idioma não é oop. Não estou dizendo que ter sessões é aconselhável. Estou apenas dando minha opinião a respeito de seguir um conjunto de práticas a ponto de não oferecerem benefícios a alguém. (Observe, não me opus a seus comentários, no entanto, eu não diria que não é REST, diria que não é REST puro ).
arg20

Então, como chamamos se não é RESTful? E, certamente, se uma solicitação incluir o ID da sessão, isso será tão apátrida quanto um pedido, incluindo um ID do usuário? Por que o ID do usuário é sem estado e o ID da sessão com estado?
Mfhholmes

1
Os cookies são vulneráveis ​​à falsificação de solicitações entre sites, facilitando a violação de segurança. Melhor usar algo que não é enviado automaticamente pelo navegador, como um cabeçalho personalizado ou um esquema de autorização personalizado.
Dobes Vandermeer

1
De fato, tentar ser apátrida não é sobre dogmatismo, mas sobre uma concepção comum da própria SOA. Os serviços devem sempre se beneficiar de serem desacoplados e apátridas: na prática, facilita o dimensionamento, a disponibilidade e a manutenção. Obviamente, deve ser o máximo possível, e você eventualmente precisará de alguns "serviços de orquestração" para gerenciar esses serviços sem estado em uma abordagem pragmática com estado.
Arnaud Bouchez

32

Em primeiro lugar, um serviço da web RESTful é STATELESS (ou, em outras palavras, SESSIONLESS ). Portanto, um serviço RESTful não possui e não deve ter um conceito de sessão ou cookies envolvidos. A maneira de realizar autenticação ou autorização no serviço RESTful é usando o cabeçalho HTTP Authorization, conforme definido nas especificações HTTP do RFC 2616. Cada solicitação única deve conter o cabeçalho de Autorização HTTP e a solicitação deve ser enviada por uma conexão HTTPs (SSL). Esta é a maneira correta de fazer autenticação e verificar a autorização de solicitações em um serviço da Web HTTP RESTful. Eu implementei um serviço da Web RESTful para o aplicativo Cisco PRIME Performance Manager na Cisco Systems. E como parte desse serviço da web, implementei autenticação / autorização também.


5
A autenticação HTTP ainda exige que o servidor acompanhe os IDs e senhas do usuário. Isso não é completamente apátrida.
Jcoffland # 03/02

21
É apátrida no sentido de que cada solicitação é válida por si só, sem quaisquer requisitos de solicitações anteriores. Como isso é implementado no servidor é outra questão, se a autenticação for cara, você poderá fazer um cache e autenticar novamente na falta de cache. Pouquíssimos servidores são completamente sem estado, onde a saída é puramente uma função da entrada. Geralmente é uma consulta ou uma atualização para algum estado.
Erik Martino

3
Não é verdade. Nesse caso, todas as suas solicitações exigem o estado de uma transação anterior, ou seja, o registro do usuário. Não vejo por que as pessoas continuam tentando dizer que um nome de usuário e senha armazenados no servidor não são do lado do servidor. Veja minha resposta.
precisa saber é o seguinte

1
@jcoffland Além disso, sua solução depende muito da capacidade do servidor da API de descriptografar o token assinado. Eu acho que essa abordagem não é apenas específica demais, mas também um pouco sofisticada demais para ser pensada como a abordagem que R. Fielding tinha em mente para resolver o problema da autenticação RESTful.
Michael Ekoka

2
@jcoffland, você entende como é a criptografia assimétrica de uso intensivo em computação (e, portanto, em uso intensivo de recursos e profundamente lento)? Você está falando de um esquema que usaria criptografia assimétrica em cada solicitação. O aspecto mais lento do HTTPS, sem exceção, é o handshake inicial que envolve a criação de chaves públicas / privadas para criptografar assimetricamente um segredo compartilhado que é subsequentemente usado para criptografar simetricamente toda a comunicação resultante.
Craig

22

Certamente, não se trata de "chaves de sessão", pois geralmente é usado para se referir à autenticação sem sessão, que é realizada dentro de todas as restrições do REST. Cada solicitação é auto-descritiva, carregando informações suficientes para autorizá-la por si própria, sem nenhum estado de aplicativo do lado do servidor.

A maneira mais fácil de abordar isso é iniciando com os mecanismos de autenticação internos do HTTP no RFC 2617 .


A autenticação HTTP requer que o servidor armazene o nome de usuário e a senha. Esse é o estado do lado do servidor e, portanto, não é estritamente REST. Veja minha resposta.
Jcoffland

3
@jcoffland: Isso simplesmente não é verdade, em ambas as contas. A primeira autenticação HTTP não requer que o servidor armazene a senha. O hash da senha é armazenado (bcrypt com mais de 8 rodadas recomendado). Segundo, o servidor não possui nenhum estado, pois o cabeçalho da autorização é enviado a cada solicitação. E se você considerar hashes de senha armazenados como estado , eles não serão mais do que as chaves públicas armazenadas.
Boris B.

1
@ Boris B., sim, eu entendo que a senha é armazenada como um hash. A senha com hash ainda é um estado específico do cliente. A diferença em armazenar uma chave pública, conforme descrito em minha solução, é que existe apenas uma chave pública, a chave pública do servidor de autenticação. Isso é muito diferente de armazenar um hash de senha por usuário. Não importa como você a veste, se o servidor armazenar uma senha para cada usuário, ele será armazenado por estado do usuário e não será 100% REST.
precisa saber é o seguinte

7
Eu não acho que armazenar uma senha com hash de usuários no servidor deva ser considerado um estado do lado do servidor. Usuários são recursos, contendo informações como nome, endereço ou senha com hash.
Codepunkt

15

O artigo 'muito perspicaz' mencionado por @skrebel ( http://www.berenddeboer.net/rest/authentication.html ) discute um método de autenticação complicado, mas realmente quebrado.

Você pode tentar visitar a página (que deveria ser visível apenas para usuários autenticados) http://www.berenddeboer.net/rest/site/authenticated.html sem nenhuma credencial de login.

(Desculpe, não posso comentar a resposta.)

Eu diria que REST e autenticação simplesmente não se misturam. REST significa sem estado, mas 'autenticado' é um estado. Você não pode ter os dois na mesma camada. Se você é um defensor do RESTful e desaprova os estados, precisa seguir o HTTPS (por exemplo, deixe o problema de segurança para outra camada).


Stripe.com diria o contrário ao seu comentário sobre REST e autenticação não misturar ..
Erik

Stateless refere-se apenas ao servidor, não ao cliente. O cliente pode se lembrar de todo o estado da sessão e enviar o que é relevante para cada solicitação.
Dobes Vandermeer

Finalmente, alguém que fala algum sentido, mas a autenticação sem estado é possível usando criptografia de chave pública. Veja minha resposta.
Jcoffland 8/08

1
O servidor não possui um estado "autenticado". Ele recebe informações via hipermídia e precisa trabalhar com ele para retornar o que foi solicitado. Nada menos, nada mais. Se o recurso estiver protegido e exigir autenticação e autorização, a hipermídia fornecida deverá incluir essas informações. Não sei de onde vem a noção de que a autenticação de um usuário antes de retornar um recurso significa que o servidor está rastreando o estado. Fornecer um nome de usuário e uma senha pode muito bem ser pensado como simplesmente fornecendo mais parâmetros de filtragem.
precisa saber é o seguinte

"Eu diria que REST e autenticação simplesmente não se misturam." Parece algum senso comum. Exceto que um sistema incompatível com a autenticação (o "autenticado" em si é, é claro, um estado) tem utilidade limitada. Sinto que todos estamos discutindo na interseção entre praticidade e dogmatismo purista, e francamente a praticidade deveria vencer. Existem muitos aspectos do REST que são altamente benéficos sem entrar em contorções, tentando evitar o estado com relação à autenticação, não é?
Craig

12

Acho que a autenticação repousante envolve a passagem de um token de autenticação como parâmetro na solicitação. Exemplos são o uso de apikeys por api's. Não acredito que o uso de cookies ou a autenticação http se qualifique.


Os cookies e a autenticação HTTP devem ser evitados devido à vulnerabilidade do CSRF.
Dobes Vandermeer

@DobesVandermeer Você pode ver minha pergunta se puder ajudar? stackoverflow.com/questions/60111743/…
Hemant Metalia

12

Atualização em 16 de fevereiro de 2019

A abordagem mencionada anteriormente abaixo é essencialmente o tipo de concessão "Credencial de senha do proprietário do recurso" do OAuth2.0 . Essa é uma maneira fácil de começar a funcionar. No entanto, com essa abordagem, todos os aplicativos da organização terão seus próprios mecanismos de autenticação e autorização. A abordagem recomendada é o tipo de concessão "Código de autorização". Além disso, na minha resposta anterior abaixo, recomendei o localStorage do navegador para armazenar tokens de autenticação. No entanto, acredito que o cookie é a opção certa para esse fim. Eu detalhei meus motivos, abordagem de implementação do tipo de concessão de código de autorização, considerações de segurança etc. nesta resposta do StackOverflow .


Eu acho que a seguinte abordagem pode ser usada para autenticação de serviço REST:

  1. Crie uma API RESTful de login para aceitar nome de usuário e senha para autenticação. Use o método HTTP POST para impedir o armazenamento em cache e o SSL para segurança durante o trânsito. Na autenticação bem-sucedida, a API retorna dois JWTs - um token de acesso (validade mais curta, digamos 30 minutos) e um token de atualização (validade mais longa, digamos 24 horas)
  2. O cliente (uma interface do usuário baseada na Web) armazena os JWTs no armazenamento local e em cada chamada subsequente da API passa o token de acesso no cabeçalho "Autorização: token de acesso ao portador"
  3. A API verifica a validade do token, verificando a assinatura e a data de validade. Se o token for válido, verifique se o usuário (interpreta a reivindicação "sub" no JWT como nome de usuário) tem acesso à API com uma pesquisa de cache. Se o usuário estiver autorizado a acessar a API, execute a lógica de negócios
  4. Se o token expirar, a API retornará o código de resposta HTTP 400
  5. O cliente, ao receber 400/401, chama outra API REST com o token de atualização no cabeçalho "Autorização: token de atualização do portador" para obter um novo token de acesso.
  6. Ao receber a chamada com token de atualização, verifique se o token de atualização é válido, verificando a assinatura e a data de validade. Se o token de atualização for válido, atualize o cache correto de acesso do usuário do DB e retorne o novo token de acesso e atualize o token. Se o token de atualização for inválido, retorne o código de resposta HTTP 400
  7. Se um novo token de acesso e token de atualização forem retornados, vá para a etapa 2. Se o código de resposta HTTP 400 for retornado, o cliente assumirá que o token de atualização expirou e solicitará o nome de usuário e a senha do usuário
  8. Para sair, limpe o armazenamento local

Com essa abordagem, estamos fazendo a operação dispendiosa de carregar o cache com os detalhes certos de acesso específico do usuário a cada 30 minutos. Portanto, se um acesso for revogado ou novo acesso for concedido, leva 30 minutos para refletir ou um logout seguido de um logon.


então você usaria isso para uma API com um site estático feito com angular, por exemplo? e quanto aos aplicativos móveis?
Yazan Rawashdeh

8

Essa é a maneira de fazer isso: usando o OAuth 2.0 para logon .

Você pode usar outros métodos de autenticação que não sejam do Google, desde que sejam compatíveis com o OAuth.


1
OAuth2 não é seguro sem HTTPS, nem sem estado.
Arnaud Bouchez

4
Nada é seguro sem HTTPS.
Craig

1
@ Craig E HTTPS podem não ser segura tanto, se a cadeia de certificados está quebrado, o que pode ser para um bem maior - en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
Arnaud Bouchez

1
@ArnaudBouchez Esclareça como ter uma cadeia de certificados quebrada é para um bem maior? Eu não entendo aonde você está indo com isso. ;)
Craig

@ Craig Siga o link e divirta-se! Essa abordagem de "bem maior" era claramente cínica em meu comentário: sistemas semelhantes a touros são destinados a "nosso próprio bem" por nossos governos amados e confiáveis.
Arnaud Bouchez

3

O uso de uma infra-estrutura de chave pública na qual o registro de uma chave envolve ligação adequada garante que a chave pública seja vinculada ao indivíduo ao qual está atribuída, de maneira a garantir não-repúdio

Veja http://en.wikipedia.org/wiki/Public_key_infrastructure . Se você seguir os padrões adequados de PKI, a pessoa ou agente que usar indevidamente a chave roubada poderá ser identificado e bloqueado. Se for necessário que o agente use um certificado, a ligação fica bastante rígida. Um ladrão inteligente e veloz pode escapar, mas deixa mais migalhas.


2

Para responder a esta pergunta do meu entendimento ...

Um sistema de autenticação que usa o REST para que você não precise realmente rastrear ou gerenciar os usuários em seu sistema. Isso é feito usando os métodos HTTP POST, GET, PUT, DELETE. Nós pegamos esses 4 métodos e pensamos neles em termos de interação com o banco de dados como CREATE, READ, UPDATE, DELETE (mas na web usamos POST e GET porque é isso que as tags âncoras suportam atualmente). Portanto, tratando POST e GET como nosso CREATE / READ / UPDATE / DELETE (CRUD), podemos projetar rotas em nosso aplicativo da Web que serão capazes de deduzir que ação do CRUD estamos realizando.

Por exemplo, em um aplicativo Ruby on Rails, podemos criar nosso aplicativo da web para que, se um usuário logado, visite http://store.com/account/logout , o GET dessa página possa ser visto como o usuário tentando fazer logout. . Em nosso controlador rails, criaríamos uma ação que desconecta o usuário e os envia de volta à página inicial.

Um GET na página de login renderia um formulário. um POST na página de login seria visto como uma tentativa de logon e pegaria os dados do POST e os usaria para efetuar login.

Para mim, é uma prática usar métodos HTTP mapeados para o significado do banco de dados e, em seguida, criar um sistema de autenticação com isso em mente que você não precisa repassar nenhum ID de sessão ou acompanhar sessões.

Ainda estou aprendendo - se você encontrar alguma coisa que eu disse estar errada, corrija-me e, se souber mais, poste aqui. Obrigado.


2

Dicas válidas para proteger qualquer aplicativo Web

Se você deseja proteger seu aplicativo, definitivamente deve começar usando HTTPS em vez de HTTP , isso garante um canal seguro de criação entre você e os usuários que evitará cheirar os dados enviados aos usuários e ajudará a mantê-los trocado confidencial.

Você pode usar JWTs (JSON Web Tokens) para proteger APIs RESTful ; isso tem muitos benefícios quando comparado às sessões do servidor, os benefícios são principalmente:

1- Mais escalável, pois seus servidores de API não precisarão manter sessões para cada usuário (o que pode ser um grande fardo quando você tiver muitas sessões)

2- Os JWTs são independentes e possuem as reivindicações que definem a função do usuário, por exemplo, o que ele pode acessar e emitido na data e data de validade (após o qual o JWT não será válido)

3- Mais fácil de lidar com balanceadores de carga e se você tiver vários servidores de API, não precisará compartilhar dados da sessão nem configurar o servidor para rotear a sessão para o mesmo servidor, sempre que uma solicitação com um JWT atingir qualquer servidor, ela pode ser autenticada e autorizado

4- Menos pressão no seu banco de dados e você não precisará armazenar e recuperar constantemente o ID da sessão e os dados para cada solicitação

5- Os JWTs não podem ser violados se você usar uma chave forte para assinar o JWT, para que possa confiar nas reivindicações no JWT enviadas com a solicitação sem precisar verificar a sessão do usuário e se ele está autorizado ou não , basta verificar o JWT e pronto para saber quem e o que esse usuário pode fazer.

Muitas bibliotecas fornecem maneiras fáceis de criar e validar JWTs na maioria das linguagens de programação, por exemplo: no node.js, uma das mais populares é jsonwebtoken

Como as APIs REST geralmente têm como objetivo manter o servidor sem estado, as JWTs são mais compatíveis com esse conceito, pois cada solicitação é enviada com o token de autorização independente (JWT) sem que o servidor tenha que acompanhar a sessão do usuário em comparação com as sessões que tornam o com estado do servidor, para que ele se lembre do usuário e de sua função; no entanto, as sessões também são amplamente usadas e têm seus profissionais, que você pode procurar se quiser.

Uma coisa importante a ser observada é que você deve entregar com segurança o JWT ao cliente usando HTTPS e salvá-lo em um local seguro (por exemplo, no armazenamento local).

Você pode aprender mais sobre JWTs neste link

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.