Estou implementando um sistema de autenticação baseado em token para uma API REST usando um token de acesso de curta duração e um token de atualização de longa duração. Esta é uma visão geral abstrata dos pontos de extremidade da API relevantes (o HTTPS é imposto a todos os pontos de extremidade):
Pontos finais:
POST /register/
POST /login/
POST /logout/
POST /password/change/
Implementação:
POST /register/
:
- Solicitação: o cliente envia nome de usuário, email e senha em JSON.
- Ações do servidor:
- Valida a entrada, cria usuário no banco de dados (armazena ID do usuário, nome de usuário, email e hash da senha).
- Cria um token de acesso de curta duração no formato JWT (contém o ID do usuário, a data de emissão e a data de validade).
- Cria um token de atualização de longa duração como uma string UUID e o armazena no banco de dados (armazena o ID do usuário e o token de atualização).
- Resposta: O servidor retorna o token de acesso e o token de atualização no JSON.
POST /login/
:
- Solicitação: o cliente envia nome de usuário e senha em JSON.
- Ações do servidor:
- Valida a entrada, verifica se as credenciais são válidas verificando o banco de dados.
- Se as credenciais forem válidas, cria um token de acesso de curta duração e um token de atualização de longa duração, conforme mencionado anteriormente.
- Resposta: O mesmo que
/register/
, retorna o token de acesso e o token de atualização no JSON.
POST /logout/
:
- Solicitação: o cliente envia o token de atualização no
Authorization
cabeçalho comoBearer
token. - Ações do servidor:
- Valida o token de atualização verificando o banco de dados do token de atualização.
- Remove o token de atualização do banco de dados.
Nota: Isso deixa o token de acesso válido, mas como ele terá vida curta (1 hora ou mais, acho que deve estar bom).
- Resposta: Retorna se a solicitação de logout foi processada com sucesso em JSON.
POST /password/change/
:
- Solicitação: o cliente envia o token de acesso no
Authorization
cabeçalho comoBearer
token e também envia a senha antiga e a nova senha no JSON por HTTPS. - Ações do servidor:
- Decodifica o token de acesso para recuperar o usuário e verifica a senha antiga do usuário no banco de dados.
- Define o hash da senha do usuário no banco de dados como o hash da nova senha.
- Remove todos os tokens de atualização associados ao usuário no banco de dados do token de atualização para efetivamente desconectar as sessões existentes (deixa válidos os tokens de acesso de curta duração).
- Resposta: Retorna se a solicitação de alteração de senha foi processada com sucesso em JSON.
Questões:
- Essa abordagem é segura? Especificamente:
- O envio do nome de usuário e da senha através do JSON é seguro se for feito por HTTPS? Como impediria que domínios não autorizados fizessem chamadas para este endpoint? Além disso, como eu evitaria logins programáticos?
- Os tokens de atualização devem ser divididos em hash antes de armazená-los no banco de dados ou estou sendo paranóico?
- Se o cliente fosse um navegador da Web, como eu armazenaria com segurança o token de atualização no cliente?
- Uma idéia que tenho para armazenar o token de atualização é: quando o usuário efetua login, além de enviar o token de atualização ao cliente, o servidor armazena o token em um
HttpOnly
cookie com umsecure
sinalizador. A autorização ainda será feita por meio doAuthorization
cabeçalho, mas quando o cliente for carregado inicialmente, ele poderá enviar umaGET
solicitação para um terminal que verifique se o cookie contém um token de atualização válido e, se houver, devolva-o ao usuário no JSON. Em outras palavras, a única vez que o cookie será realmente usado é retornar o token de atualização dentro do cookie para o cliente. Essa abordagem é segura? Acho que isso impedirá o CSRF, pois não há efeitos colaterais ao solicitar o token de atualização do cookie, mas existe outra maneira de um invasor interceptar o token de atualização (assumindo HTTPS)?
- Uma idéia que tenho para armazenar o token de atualização é: quando o usuário efetua login, além de enviar o token de atualização ao cliente, o servidor armazena o token em um