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
Respostas:
Sim. Cabeçalhos, parâmetros de solicitação e corpo da solicitação são criptografados durante a comunicação.
Uma vez no lado do servidor, não registre o corpo da solicitação :-)
Você não pode. Basicamente, quando a API está na WWW, é automaticamente exposta a todo tipo de malícia. O melhor que você pode fazer é estar preparado e estar ciente das ameaças. Pelo menos sobre aqueles que lhe dizem respeito. Dê uma olhada aqui .
Uma possível abordagem para o problema poderia estar implementando (ou contratando) um API Manager .
Os gerentes de API locais podem reduzir a superfície de ataque porque todos os pontos de extremidade atrás da AM não são necessariamente públicos.
Você pode obter o mesmo resultado com alguns produtos na nuvem, mas eles são absurdamente caros para o mainstream.
De qualquer forma, os pontos de extremidade do Gerenciamento de API permanecerão expostos a ataques.
Se por logins programáticos você quer dizer ataques por força bruta, um limite (número máximo de solicitações permitidas por segundo) e uma lista negra devem ser suficientes para impedir a insistência do invasor. Para mais informações, dê uma olhada aqui .
Muitos dos gerentes de API fornecem configurações e limites de taxa de API prontos para uso .
Se você conhece o Google API Console, pode adivinhar o que um API Manager pode fazer.
Se o token de atualização é um UUID simples ou qualquer outra coisa, não gosto de expor esse tipo de detalhe de implementação. Então, eu sugiro hash. Para mim, quanto mais opacos forem os detalhes de implementação da camada de segurança, melhor.
Em relação à segurança do JWT, dê uma olhada aqui .
Você pode estar interessado em JSON Web Token (JWT) - armazenamento no lado do cliente .
fonte
sessionStorage
que não funcionem. Além disso,localStorage
edocument.cookie
parecem inseguros, pois podem ser acessados por JavaScript. Minha abordagem faz sentido ou é potencialmente insegura?document.cookie
um cookie HttpOnly com um sinalizador seguro, semelhante à abordagem mencionada acima?