Ao criar aplicativos no estilo SPA usando estruturas como Angular, Ember, React etc. etc., quais são as melhores práticas para autenticação e gerenciamento de sessões? Posso pensar em algumas maneiras de considerar abordar o problema.
Trate-o de maneira diferente da autenticação com um aplicativo Web regular, assumindo que a API e a UI tenham o mesmo domínio de origem.
Isso provavelmente envolveria ter um cookie de sessão, armazenamento de sessão no servidor e provavelmente um ponto de extremidade da API da sessão que a interface do usuário da web autenticada pode acessar para obter informações atuais do usuário para ajudar na personalização ou possivelmente até na determinação de funções / habilidades no lado do cliente. O servidor ainda aplicaria regras que protegem o acesso aos dados, é claro, a interface do usuário apenas usaria essas informações para personalizar a experiência.
Trate-o como qualquer cliente de terceiros usando uma API pública e autentique com algum tipo de sistema de token semelhante ao OAuth. Esse mecanismo de token seria usado pela interface do usuário do cliente para autenticar toda e qualquer solicitação feita à API do servidor.
Não sou muito especialista aqui, mas o número 1 parece ser suficiente para a grande maioria dos casos, mas eu realmente gostaria de ouvir opiniões mais experientes.
fonte
Respostas:
Esta questão foi abordada, de uma forma ligeiramente diferente, detalhadamente aqui:
Autenticação RESTful
Mas isso aborda do lado do servidor. Vejamos isso do lado do cliente. Antes de fazer isso, porém, há um prelúdio importante:
O Javascript Crypto é impossível
O artigo de Matasano sobre isso é famoso, mas as lições nele contidas são muito importantes:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
Para resumir:
<script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
E para adicionar um corolário meu:
Isso torna muitos esquemas de autenticação RESTful impossíveis ou tolos se você pretende usar um cliente JavaScript. Vamos olhar!
Autenticação básica HTTP
Em primeiro lugar, o HTTP Basic Auth. O mais simples dos esquemas: basta passar um nome e senha a cada solicitação.
Obviamente, isso exige absolutamente SSL, porque você passa um nome e uma senha codificados em Base64 (reversivelmente) a cada solicitação. Qualquer pessoa que escute na linha poderá extrair nome de usuário e senha trivialmente. A maioria dos argumentos "A autenticação básica é insegura" vem de um local "A autenticação básica sobre HTTP", que é uma péssima idéia.
O navegador fornece suporte básico à autenticação HTTP básica, mas é feio como o pecado e você provavelmente não deve usá-lo no seu aplicativo. A alternativa, porém, é esconder o nome de usuário e a senha em JavaScript.
Esta é a solução mais RESTful. O servidor não requer nenhum conhecimento do estado e autentica todas as interações individuais com o usuário. Alguns entusiastas do REST (principalmente homens de palha) insistem que manter qualquer tipo de estado é uma heresia e se espalhará pela boca se você pensar em outro método de autenticação. Existem benefícios teóricos para esse tipo de conformidade com os padrões - com o Apache pronto para uso - você pode armazenar seus objetos como arquivos em pastas protegidas por arquivos .htaccess, se desejar.
O problema ? Você está armazenando em cache no lado do cliente um nome de usuário e senha. Isso dá ao evil.ru uma solução melhor - mesmo as vulnerabilidades mais básicas do XSS podem resultar no cliente transferir seu nome de usuário e senha para um servidor inválido. Você pode tentar aliviar esse risco usando hash e salgando a senha, mas lembre-se: o JavaScript Crypto é impossível . Você pode aliviar esse risco deixando-o para o suporte de autenticação básica do navegador, mas feio como o pecado, como mencionado anteriormente.
Autenticação de resumo HTTP
A autenticação Digest é possível com o jQuery?
Uma autenticação mais "segura", este é um desafio de hash de solicitação / resposta. Exceto que o JavaScript Crypto é impossível , portanto, ele funciona apenas com SSL e você ainda precisa armazenar em cache o nome de usuário e a senha no lado do cliente, tornando-o mais complicado que o HTTP Basic Auth, mas não mais seguro .
Autenticação de consulta com parâmetros de assinatura adicionais.
Outra autenticação mais "segura", na qual você criptografa seus parâmetros com dados não temporários e de tempo (para proteger contra ataques de repetição e tempo) e envia o arquivo. Um dos melhores exemplos disso é o protocolo OAuth 1.0, que é, até onde eu sei, uma maneira bastante difícil de implementar a autenticação em um servidor REST.
http://tools.ietf.org/html/rfc5849
Ah, mas não há clientes OAuth 1.0 para JavaScript. Por quê?
JavaScript Crypto é impossível , lembre-se. O JavaScript não pode participar do OAuth 1.0 sem SSL, e você ainda precisa armazenar o nome de usuário e a senha do cliente localmente - o que o coloca na mesma categoria que o Digest Auth - é mais complicado que o HTTP Basic Auth, mas não é mais seguro .
Símbolo
O usuário envia um nome de usuário e senha e, em troca, recebe um token que pode ser usado para autenticar solicitações.
Isso é marginalmente mais seguro que o HTTP Basic Auth, porque assim que a transação de nome de usuário / senha é concluída, você pode descartar os dados confidenciais. Também é menos RESTful, pois os tokens constituem "estado" e tornam a implementação do servidor mais complicada.
Ainda SSL
O problema, porém, é que você ainda precisa enviar esse nome de usuário e senha iniciais para obter um token. Informações confidenciais ainda tocam no seu JavaScript comprometível.
Para proteger as credenciais do usuário, você ainda precisa manter os invasores fora do seu JavaScript e ainda precisa enviar um nome de usuário e senha pelo telefone. SSL obrigatório.
Expiração de token
É comum impor políticas de token como "ei, quando esse token já existe há muito tempo, descarte-o e faça o usuário se autenticar novamente". ou "Tenho certeza de que o único endereço IP permitido para usar esse token é
XXX.XXX.XXX.XXX
". Muitas dessas políticas são boas idéias.Firesheeping
No entanto, o uso de um token Without SSL ainda é vulnerável a um ataque chamado 'sidejacking': http://codebutler.github.io/firesheep/
O invasor não obtém as credenciais do usuário, mas ainda pode fingir ser seu usuário, o que pode ser muito ruim.
tl; dr: O envio de tokens não criptografados por cabo significa que os invasores podem facilmente pegá-los e fingir ser seu usuário. O FireSheep é um programa que facilita muito isso.
Uma zona separada e mais segura
Quanto maior o aplicativo em execução, mais difícil é garantir absolutamente que eles não possam injetar algum código que mude a maneira como você processa dados confidenciais. Você confia absolutamente no seu CDN? Seus anunciantes? Sua própria base de código?
Comum para detalhes de cartão de crédito e menos comum para nome de usuário e senha - alguns implementadores mantêm 'entrada de dados confidenciais' em uma página separada do restante do aplicativo, uma página que pode ser rigidamente controlada e bloqueada da melhor forma possível, de preferência uma que é difícil phishing usuários com.
Cookie (apenas significa Token)
É possível (e comum) colocar o token de autenticação em um cookie. Isso não altera nenhuma das propriedades de auth com o token, é mais uma coisa de conveniência. Todos os argumentos anteriores ainda se aplicam.
Sessão (ainda significa apenas token)
A autenticação de sessão é apenas autenticação de token, mas com algumas diferenças que fazem parecer uma coisa um pouco diferente:
Além disso, porém, não é diferente do Token Auth, na verdade.
Isso se afasta ainda mais de uma implementação RESTful - com objetos de estado, você está indo cada vez mais longe do caminho da RPC simples em um servidor com estado.
OAuth 2.0
O OAuth 2.0 analisa o problema de "Como o Software A concede ao Software B acesso aos dados do Usuário X sem que o Software B tenha acesso às credenciais de login do Usuário X".
A implementação é apenas uma maneira padrão de um usuário obter um token e, em seguida, de um serviço de terceiros "sim, esse usuário e esse token correspondem, e você pode obter alguns dos dados deles agora".
Fundamentalmente, porém, o OAuth 2.0 é apenas um protocolo de token. Ele exibe as mesmas propriedades que outros protocolos de token - você ainda precisa de SSL para proteger esses tokens - apenas altera a forma como esses tokens são gerados.
Há duas maneiras pelas quais o OAuth 2.0 pode ajudá-lo:
Mas quando se trata disso, você está apenas ... usando tokens.
Voltar à sua pergunta
Portanto, a pergunta que você está perguntando é "devo armazenar meu token em um cookie e fazer com que o gerenciamento automático de sessões do meu ambiente cuide dos detalhes ou devo armazenar meu token em Javascript e lidar com esses detalhes sozinho?"
E a resposta é: faça o que te faz feliz .
O problema do gerenciamento automático de sessões é que há muita mágica acontecendo nos bastidores para você. Muitas vezes, é melhor controlar você mesmo esses detalhes.
Tenho 21 anos, então o SSL é sim
A outra resposta é: use https para tudo ou bandidos roubam as senhas e os tokens dos usuários.
fonte
It's also less RESTful, as tokens constitute "state and make the server implementation more complicated."
REST do token (1) requer que o servidor seja sem estado. Um token armazenado no lado do cliente não representa o estado de maneira significativa para o servidor. (2) Código marginalmente mais complicado do lado do servidor não tem nada a ver com RESTfulness.lol_nope_send_it_to_me_instead
Eu amei o nome dessa função: DVocê pode aumentar a segurança no processo de autenticação usando JWT (JSON Web Tokens) e SSL / HTTPS.
A identificação básica de autenticação / sessão pode ser roubada via:
Ao usar o JWT, você criptografa os detalhes de autenticação do usuário e armazena no cliente, enviando-o juntamente com todas as solicitações para a API, onde o servidor / API valida o token.
Ele não pode ser descriptografado / ler sem a chave privada (que o / lojas API secretamente servidor)Leia atualização .O novo fluxo (mais seguro) seria:
Conecte-se
Toda solicitação para API
Atualizado 30.07.15:
A carga / reivindicações do JWT pode realmente ser lida sem a chave privada (secreta) e não é seguro armazená-la no localStorage. Sinto muito por essas declarações falsas. No entanto, eles parecem estar trabalhando em um padrão JWE (JSON Web Encryption) .
Eu implementei isso armazenando declarações (ID do usuário, exp) em um JWT, assinei-a com uma chave privada (segredo) que a API / backend apenas conhece e a armazene como um cookie HttpOnly seguro no cliente. Dessa forma, ele não pode ser lido via XSS e não pode ser manipulado; caso contrário, o JWT falhará na verificação da assinatura. Além disso, usando um cookie HttpOnly seguro , você garante que o cookie seja enviado apenas por solicitações HTTP (não acessível ao script) e enviado apenas por conexão segura (HTTPS).
Atualizado 17.07.16:
Os JWTs são por natureza apátridas. Isso significa que eles se invalidam / expiram. Ao adicionar o SessionID nas declarações do token, você está tornando-o com estado, porque sua validade agora não depende apenas da verificação da assinatura e da data de validade, mas também do estado da sessão no servidor. No entanto, a vantagem é que você pode invalidar tokens / sessões facilmente, o que não era possível antes com JWTs sem estado.
fonte
Eu iria para o segundo, o sistema de token.
Você sabia sobre ember-auth ou ember-simple-auth ? Ambos usam o sistema baseado em token, como estados ember-simple-auth:
Eles possuem gerenciamento de sessões e também são fáceis de conectar a projetos existentes.
Há também uma versão de exemplo do Ember App Kit do ember-simple-auth: Exemplo de trabalho do ember-app-kit usando o ember-simple-auth para autenticação OAuth2.
fonte