Estou trabalhando em uma API para um serviço REST que vou produzir e consumir. Passei os últimos dias tentando descobrir como lidar bem com a autenticação e acho que finalmente criei algo.
Estou apresentando isso com base nos seguintes fatos sobre a pilha de aplicativos:
- Cliente e servidor estão no .NET4 (parte do cliente no perfil do cliente)
- O servidor expõe usando o WCF REST
- Eu realmente não quero manter o nome de usuário e a senha na memória do aplicativo
Em 3, eu queria usar uma forma de autenticação de token, para que, depois que as credenciais sejam verificadas pelo servidor, o cliente receba um token novamente para uso em todo o resto do aplicativo (isso permitirá que eu faça outras coisas, como atingir o tempo limite dos usuários, podendo mover os usuários sem problemas entre as versões da Web e da área de trabalho, etc). Depois de descobrir como fazer com que as chamadas sejam reproduzidas e resistentes a violações, vim com o seguinte:
- Antes de o cliente tentar se autenticar, ele gera um par de chaves Diffie-Hellman usando a
ECDiffieHellmanCng
classe - Ele envia a parte pública do par de chaves pela conexão, juntamente com o nome do usuário e a senha (sobre HTTPS, é claro).
- O servidor autentica a combinação de nome de usuário / senha, se for bem-sucedida, faz o seguinte:
- Cria um token de sessão exclusivo
- Gera seu próprio par de chaves DH e calcula o segredo compartilhado da chave pública fornecida pelo cliente
- Anota o token da sessão, o segredo compartilhado, o usuário e o tempo da "última ação" (usada para uma janela de expiração contínua) em seu banco de dados
- Retorna o token da sessão, sua chave DH pública e uma mensagem de sucesso de autenticação
- O cliente pega a chave DH da resposta, calcula o segredo compartilhado e armazena o token e o segredo na memória.
A partir desse momento, a combinação de token / segredo da sessão funciona como a maioria das outras APIs REST, com a solicitação sendo impressa por dedo e com registro de data e hora e, em seguida, gera algum tipo de HMAC. Sempre que um cliente executa uma ação no servidor, ele verifica o par de token / segredo, permite a ação se é válida e não expirou e atualiza o último registro de ação na sessão.
Não vejo falhas óbvias e provavelmente estou com excesso de engenharia para isso, mas preciso aprender como fazer isso em algum momento. O HMAC evita ataques de repetição, a negociação do DH ajuda a impedir ataques do MITM (não consigo pensar em um ataque viável do alto da minha cabeça entre o HMAC / DH).
Algum buraco que alguém possa fazer?