paint-brush
Projetando sistemas funcionais de autenticação e autorizaçãopor@iarunava
3,201 leituras
3,201 leituras

Projetando sistemas funcionais de autenticação e autorização

por Arunava12m2024/05/05
Read on Terminal Reader

Muito longo; Para ler

Neste artigo falaremos sobre um sistema para realizar autenticação e autorização com segurança.
featured image - Projetando sistemas funcionais de autenticação e autorização
Arunava HackerNoon profile picture
0-item

Neste artigo falaremos sobre um sistema para realizar autenticação e autorização com segurança. Para começar, vamos entender qual é a diferença entre autenticação e autorização.


  • Autenticação é o processo de provar que você é, quem diz ser, ao acessar um aplicativo.
  • Autorização é o processo de definição e aplicação de políticas de acesso – ou seja, o que você pode fazer depois de autenticado.

Neste artigo, veremos:



Por que a autenticação e a autorização são importantes?

Autenticação e Autorização (fonte: Jeffrey Marvin Forones|Geek Culture. Modificado)


Digamos que estamos em uma reunião e você é o líder da conversa. Para solicitar atualizações/status de algo para a pessoa certa, você precisa identificar (ou seja, autenticar ) a pessoa. Mesmo para compartilhar alguns dados confidenciais com uma pessoa, é necessário autenticar a pessoa corretamente. E é aí que entra a autenticação.


Agora digamos que, na mesma reunião, algumas decisões precisam ser tomadas. Então, para isso, devem ser as pessoas que têm o direito de tomar essas decisões que atendem a chamada, não podemos simplesmente permitir que todos façam tudo. Obviamente, algumas pessoas não estão preparadas o suficiente para tomar algumas decisões, e algumas com certeza tentarão tirar o pior proveito disso. Então isso traz Authorization , que dá a certas pessoas os direitos de permissão para determinadas atividades.

Como funciona a autenticação?

Autenticação Baseada em Token; Token de acesso e token de atualização [SPA=SinglePageApplication, RT=RefreshToken, AT=AccessToken, RS=RefreshServer, AS=AuthorizationServer] (Fonte: Okta)


Para autenticar uma pessoa, podemos atribuir uma frase única a cada pessoa, e dada a pessoa diz a frase corretamente e seu nome. Podemos dizer que ok, identificamos a pessoa. Esta é a abordagem usual para nomes de usuários e senhas. Quando as credenciais corretas são fornecidas, um sistema considera a identidade válida e concede acesso. Isso é conhecido como 1FA ou autenticação de fator único (SFA).


SFA é considerado bastante inseguro. Por que? Porque os usuários são notoriamente ruins em manter suas informações de login seguras. A autenticação multifator (MFA) é uma alternativa mais segura que exige que os usuários comprovem sua identidade de mais de uma maneira. Algumas dessas formas são:


  • Números PIN/OTP de uso único
  • Aplicativos de autenticação executados por terceiros seguros (por exemplo, Google/Microsoft Authenticator)
  • Biometria


Uma vez autenticada, a pessoa continuaria realizando ações livremente no aplicativo. E espera-se que o aplicativo tenha a pessoa reconhecida ao longo de sua jornada sem esquecê-la. Idealmente, seria demais pedir ao usuário que fornecesse a senha toda vez que ele mudasse para uma página diferente ou realizasse alguma atividade. Portanto, precisamos de uma maneira de manter o usuário autenticado depois de inserir suas credenciais e ter sido autenticado uma vez. Isso é chamado de gerenciamento de sessão .


2 maneiras de manter o usuário autenticado:

  • Autenticação baseada em sessão : quando um usuário faz login em um site em um navegador, o servidor cria uma sessão para esse usuário e atribui um ID de sessão. Este sessionid é armazenado pelo servidor para referência e enviado de volta ao usuário para ser armazenado em um cookie no navegador. Agora, cada vez que o usuário fizer uma solicitação, o navegador enviará o ID da sessão junto com a solicitação. O que ajudará na autenticação da solicitação. E, assim, preservando a autenticação enquanto o usuário estiver no site.
  • Autenticação baseada em token : Para isso, o servidor cria um token criptografado que é enviado ao usuário e salvo apenas pelo navegador, como HttpOnly Cookies. Todas as informações necessárias, como informações do usuário, permissões e expiração do token, são criptografadas dentro do token. O token é enviado para chamadas ao servidor. O servidor simplesmente descriptografa o token com a chave secreta e verifica o usuário. Este token é atualizado em intervalos.


As principais diferenças entre essas duas abordagens seriam que a autenticação baseada em token é Stateless , porque o token não precisa ser armazenado no lado do servidor. Mas para autenticação baseada em sessão, o token também precisa ser armazenado no lado do servidor, o que o torna Stateful . O que traz complicações, quando o sistema é dimensionado ou o número de usuários aumenta.


Para autenticação baseada em token, usamos principalmente JWTs (JSON Web Tokens).

Como funciona a autorização?

Controle de autorização baseado em função (RBAC) (fonte: Ajay Shekhawat | Dribble)

Depois que o usuário for autenticado, ainda precisaremos garantir que ele só terá permissão para acessar os recursos para os quais tem permissão de acesso. O acesso não autorizado a dados confidenciais pode ser um desastre. Pelo princípio do menor privilégio, as empresas normalmente estabeleceriam políticas de acesso de modo que, por padrão, você tivesse acesso ao que é absolutamente necessário para você. E então, em progressão, você terá acesso adicional. As formas comuns de segmentar o acesso são:


  • Controle de acesso baseado em função (RBAC) : os usuários são atribuídos a um determinado grupo/função que vem com permissões definidas. Exemplos: administrador, membro, proprietário.
  • Controle de acesso baseado em políticas (PBAC) : determina dinamicamente os privilégios de acesso durante a autorização com base em políticas e regras. As políticas são baseadas em funções de usuário, funções de trabalho e requisitos organizacionais.
  • Controle de acesso baseado em atributos (ABAC) : Os usuários têm acesso permitido de acordo com atributos como título, certificação, treinamento e/ou fatores ambientais como localização.
  • Listas de controle de acesso (ACLs) : cada usuário ou entidade possui permissões individuais que podem ser ativadas ou desativadas, semelhante a instalar um novo aplicativo em seu telefone e decidir quais permissões conceder (serviços de localização, contatos, etc.)


Uma tela para Listas de Controle de Acesso (fonte: Povio)


ACL é frequentemente usada em nível granular do que ABAC ou RBAC - por exemplo, para conceder acesso a usuários individuais a um determinado arquivo. ABAC e RBAC são geralmente instituídos como políticas para toda a empresa.


Projeto do sistema de autenticação

Projeto do sistema de autenticação e autorização (fonte: InterviewPen. Modificado)

Requisitos

Vamos primeiro começar definindo os requisitos funcionais do sistema:

  • Registro : permite que os usuários se registrem fornecendo as informações necessárias.
  • Login : Autentique usuários com base em suas credenciais.
  • Gerenciamento de sessões : gerencie com eficiência as sessões dos usuários para garantir a segurança.
  • Recuperação de senha : fornece um processo seguro para os usuários recuperarem suas senhas.
  • Controle de acesso : defina funções e permissões para diferentes tipos de usuários.
  • Trilha de auditoria : mantenha registros detalhados de eventos de autenticação para auditoria.
  • Desempenho : Garanta baixa latência e tempos de resposta rápidos.


Alguns requisitos não funcionais que não consideraremos no escopo deste artigo são:

  • Autenticação multifator (MFA) : implemente um sistema MFA robusto.
  • Segurança : Priorize a segurança dos dados por meio de criptografia, armazenamento seguro e comunicação segura.
  • Escalabilidade : Projete o sistema para lidar com um número crescente de usuários e transações.
  • Confiabilidade : Minimize o tempo de inatividade do sistema e garanta alta disponibilidade.
  • Usabilidade : Desenvolva uma interface de usuário intuitiva para uma experiência perfeita.


Estimativa de capacidade

Estimativa de tráfego

Primeiro, vamos começar com a estimativa de tráfego . Supondo um tráfego médio de 100.000 por mês. Estimamos um tráfego de 100 mil usuários por mês. O que se traduz em 0,04 solicitações por segundo. Precisaríamos responder a cada solicitação dentro de 500ms em 90% do tempo, ou seja, exigimos uma latência p90 de 500ms.


 assumed_traffic_per_month = 100000 #requests assumed_traffic_per_day = assumed_traffic_per_month / 30 ~= 3350 (assuming on higher end; 3333.33 to be precise) estimated_time_per_request = 500 #ms; P90 of 500ms traffic_per_second = (assumed_traffic_per_month) / (30*24*60*60) = 0.04


Objetivo de nível de serviço (SLO) : 500 ms (latência máxima aceitável, independente da carga no sistema) A capacidade média que 1 instância pode assumir, com base em nossos cálculos, é de aproximadamente 35 ms para atender uma solicitação, assumindo que não haja processamento pesado acontecendo para o pedido específico.


Vamos gerar mais duas métricas derivadas usando as métricas acima.

  • Capacidade : Backlog aceitável por instância: Número máximo de solicitações (carga) que podem ser aceitas por uma instância, sem comprometer o SLO.
  • Demanda : Backlog por instância: Número total de solicitações (carga) que fluem para uma unidade/instância com base no tráfego atual.

Por isso,

 SLO = 500ms approx_response_time_for_one_request = 35 #ms capacity = SLO/approx_response_time_for_one_request = 500 / 35 ~= 20 load_on_one_instance = 0.04 instances_available = 1 demand = traffic_per_second / instances_available = 0.04


Com a demanda e a capacidade disponíveis, vamos calcular o número total de instâncias necessárias.

 total_units_required = demand / capacity = 0.04 / 20 = 0.002 ~= 1

Assim, seríamos facilmente capazes de lidar com 100 mil solicitações por mês, com 0,04 solicitações por segundo, com 1 instância. Onde cada unidade pode lidar com 20 solicitações por segundo sem comprometer o SLO.


Estimativa de armazenamento

Idealmente, precisaríamos armazenar os detalhes de cada usuário para autenticação e autorização de acesso. Supondo que 5kb/usuário

 monthly_new_users = 500 monthly_additional_storage = 500 * 5kb = 2500kb ~= 2GB


Portanto, todos os meses, presumindo que integraremos 500 novos usuários, precisaremos de 2 GB a mais de armazenamento. Caso queiramos manter logs de autenticação. Espera-se que cada solicitação de autenticação leve 2 KB para ser armazenada.

 auth_request_size = 2kb #assumption monthly_storage = monthly_visitors * auth_request_size = 100,000 * 2KB ~= 200MB

Assim, a cada mês precisaríamos de 200 MB adicionais, assumindo um tráfego mensal de 100k.

Projeto de banco de dados

Agora que concluímos a estimativa da capacidade. Vamos criar os esquemas do banco de dados necessários para suportar os requisitos funcionais.

Esquema de banco de dados de autenticação e autorização

Vamos examinar rapidamente as tabelas. Estamos usando 6 tabelas.

  1. Usuários - Para armazenar todas as informações do usuário
  2. Credenciais - Para armazenar as credenciais de acesso/atualização assim que o usuário for autorizado.
  3. Senhas - Para armazenar as senhas de usuário criptografadas do usuário.
  4. PasswordRequests - Para armazenar as solicitações de alteração de senha que chegam para um determinado usuário.
  5. Sessões - Para armazenar quando o usuário teve uma sessão ativa e quando foi sua última atividade.
  6. ActivityApproval - Para armazenar solicitações de aprovação para uma atividade realizada por um determinado usuário, que seria verificada pelo administrador.


Design de alto nível para o sistema de autenticação

Autenticação e Autorização HLD

Terminais do sistema

Ponto final

Descrição

/Conecte-se

Autentique as credenciais do usuário.

/sair

Encerre a sessão do usuário e revogue os tokens de autenticação.

/registro

Crie um novo usuário.

/atualização/:userId

Atualize as informações do usuário.

/delete/:userId

Exclua uma conta de usuário.

/grant/:userId/:permission

Conceda permissões específicas a um usuário.

/revoke/:userId/:permission

Revogar permissões de um usuário.

/check/:userId/:recurso

Verifique o acesso do usuário a um recurso específico.

/criar/:userId

Crie uma nova sessão de usuário.

/expirar/:sessionId

Expire uma sessão de usuário.

/validar/:sessionId

Valide uma sessão de usuário ativa.


Cumprimento de Requisitos

Agora, com tudo pronto, vamos ver como podemos cumprir todos os requisitos.


Cadastro


  • Requisito - Quando um novo usuário visita nosso aplicativo. Precisamos armazenar os detalhes do usuário para que possamos autorizar/identificar o usuário na próxima vez que ele visitar.
  • Cumprido - Quando um novo usuário visita o aplicativo e insere os dados do usuário junto com seu e-mail e senha. Isso será capturado no banco de dados. Os detalhes do usuário serão armazenados na tabela Usuário. E a senha será armazenada na tabela de credenciais de forma criptografada.


Conecte-se

  • Requisito - Quando um usuário existente visita nosso aplicativo. Precisamos identificar o usuário para que possamos autorizar/identificar suas ações e mostrar-lhe os dados que lhe pertencem.
  • Cumprido - Quando um usuário existente visita o aplicativo e insere seus dados, email e senha. Fazemos o hash da senha e comparamos o hash com o hash armazenado para o usuário na tabela de credenciais. Se corresponder, conseguimos identificar o usuário com sucesso. Caso contrário, eles precisarão inserir a senha correta que inseriram durante o registro. Este processo é denominado Autenticação .


Gerenciamento de sessão

  • Requisito - Quando um usuário se autentica, inserindo seu usuário e senha. Precisamos ter certeza de que eles permaneçam conectados enquanto executam suas ações futuras/tentam ver dados confidenciais, sem que eles digitem sua senha novamente e novamente.
  • Cumprido - Quando o usuário se autentica com sucesso. O servidor de autenticação compartilhará 2 tokens com o cliente. Um access_token e um refresh_token . O access_token pode conter dados criptografados e tem um curto prazo de validade por motivos de segurança. Assim que o cliente tiver o access_token, ele o envia de volta junto com cada solicitação, o que ajuda na autenticação da solicitação. Quando o access_token expirar, o cliente deverá solicitar um novo access_token usando o refresh_token fornecido. Isso ajuda na manutenção de uma sessão.


Recuperação de senha

  • Requisito - Quando um usuário esquece sua senha, ele precisa ser capaz de redefini-la com segurança.
  • Cumprido - Quando o usuário esquecer sua senha, ele poderá enviar seu endereço de e-mail na página de senha esquecida, e nós geraremos um código único e enviaremos o link para seu e-mail. Quando o usuário clica neste link com o código e endereço de e-mail. Seremos capazes de identificar com segurança que a solicitação de recuperação de senha é autêntica. E forneça ao usuário para definir sua nova senha. E assim poder recuperar a senha.


Controle de acesso

  • Requisito - Quando um usuário realiza uma determinada ação, precisamos ter certeza de que o usuário está autenticado para realizar aquela ação e só então permitir que a ação aconteça.
  • Cumprida - Manteremos uma lista de ações, digamos de 1 a 12, para simplificar. Para cada usuário manteremos as ações autenticadas desse usuário. Agora digamos que o usuário tente executar uma ação #id 4. Verificaremos se o usuário tem permissão para executar a ação 4. Se sim, prosseguiremos e concluiremos a solicitação. Caso contrário, mostramos que a solicitação não foi bem-sucedida por falta de permissões.


Trilha de auditoria

  • Requisito - No caso de um incidente de segurança, devemos ser capazes de ter registros suficientes para examinar e ter uma razão plausível sobre o que pode ter acontecido/ou qualquer pista sobre o que poderia ter sido uma possível causa disso.
  • Cumprido – Para tais cenários, podemos manter logs para cada ação de autenticação que acontece no servidor. (a). Para cada solicitação de login, manteremos um registro de quando ocorreu a autenticação, de onde, ips e outros detalhes relevantes. (b). Para cada solicitação de recuperação de senha, manteremos um registro de quando foi iniciada, de onde, ips, se a solicitação foi concluída e outros detalhes relevantes. (c). Além disso, manteremos registros sempre que um usuário for autorizado/não autorizado para uma ação e por quem. Ao todo, esses logs devem ser capazes de indicar o que pode ter acontecido caso você tente entender algum cenário.


Desempenho

  • Requisito - O requisito de desempenho, conforme discutido na seção de estimativa de capacidade, é de 0,04 solicitações/segundo e 100 mil solicitações por mês.
  • Cumprido - Já tratamos do requisito com servidores suficientes na seção de estimativa de capacidade.

Conclusão

Autenticação vs Autorização (fonte: OutSystems)

Neste artigo, começamos entendendo qual é a diferença entre Autenticação e Autorização. A seguir, criamos um Sistema de Autenticação e Autorização. Isso é seguro, oferece desempenho e atende aos padrões do setor e atende a todos os requisitos desejados. No futuro, posso atualizar certas partes do artigo para torná-lo relevante, bem como para cobrir mais informações e insights na construção de tal sistema.