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. é o processo de provar que você é, quem diz ser, ao acessar um aplicativo. Autenticação é o processo de definição e aplicação de políticas de acesso – ou seja, o que você pode fazer depois de autenticado. Autorização Neste artigo, veremos: Por que a autenticação e a autorização são importantes Como funciona a autenticação Como funciona a autorização Projeto do sistema de autenticação Conclusão Por que a autenticação e a autorização são importantes? 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, ) a pessoa. Mesmo para compartilhar alguns dados confidenciais com uma pessoa, é necessário autenticar a pessoa corretamente. E é aí que entra a autenticação. autenticar 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 , que dá a certas pessoas os direitos de permissão para determinadas atividades. Authorization Como funciona a autenticação? 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 (SFA). autenticação de fator único 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: : 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 sessão : 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. Autenticação baseada em token As principais diferenças entre essas duas abordagens seriam que a autenticação baseada em token é , 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 . O que traz complicações, quando o sistema é dimensionado ou o número de usuários aumenta. Stateless Stateful Para autenticação baseada em token, usamos principalmente JWTs (JSON Web Tokens). Como funciona a autorização? 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: : 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 função (RBAC) : 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 políticas (PBAC) : Os usuários têm acesso permitido de acordo com atributos como título, certificação, treinamento e/ou fatores ambientais como localização. Controle de acesso baseado em atributos (ABAC) : 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.) Listas de controle de acesso (ACLs) 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 Requisitos Vamos primeiro começar definindo os do sistema: requisitos funcionais : permite que os usuários se registrem fornecendo as informações necessárias. Registro : Autentique usuários com base em suas credenciais. Login : gerencie com eficiência as sessões dos usuários para garantir a segurança. Gerenciamento de sessões : fornece um processo seguro para os usuários recuperarem suas senhas. Recuperação de senha : defina funções e permissões para diferentes tipos de usuários. Controle de acesso : mantenha registros detalhados de eventos de autenticação para auditoria. Trilha de auditoria : Garanta baixa latência e tempos de resposta rápidos. Desempenho Alguns que não consideraremos no escopo deste artigo são: requisitos não funcionais : implemente um sistema MFA robusto. Autenticação multifator (MFA) : Priorize a segurança dos dados por meio de criptografia, armazenamento seguro e comunicação segura. Segurança : Projete o sistema para lidar com um número crescente de usuários e transações. Escalabilidade : Minimize o tempo de inatividade do sistema e garanta alta disponibilidade. Confiabilidade : Desenvolva uma interface de usuário intuitiva para uma experiência perfeita. Usabilidade Estimativa de capacidade Estimativa de tráfego Primeiro, vamos começar com . 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. a estimativa de tráfego 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 : 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. Objetivo de nível de serviço (SLO) Vamos gerar mais duas usando as métricas acima. métricas derivadas : 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. Capacidade : Backlog por instância: Número total de solicitações (carga) que fluem para uma unidade/instância com base no tráfego atual. Demanda 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. Vamos examinar rapidamente as tabelas. Estamos usando 6 tabelas. Usuários - Para armazenar todas as informações do usuário Credenciais - Para armazenar as credenciais de acesso/atualização assim que o usuário for autorizado. Senhas - Para armazenar as senhas de usuário criptografadas do usuário. PasswordRequests - Para armazenar as solicitações de alteração de senha que chegam para um determinado usuário. Sessões - Para armazenar quando o usuário teve uma sessão ativa e quando foi sua última atividade. 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 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 - 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. Requisito - 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. Cumprido Conecte-se - 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. Requisito - 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 . Cumprido Autenticação Gerenciamento de sessão - 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. Requisito - Quando o usuário se autentica com sucesso. O servidor de autenticação compartilhará 2 tokens com o cliente. Um e um . 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. Cumprido access_token refresh_token Recuperação de senha - Quando um usuário esquece sua senha, ele precisa ser capaz de redefini-la com segurança. Requisito - 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. Cumprido Controle de acesso - 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. Requisito - 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. Cumprida Trilha de auditoria - 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. Requisito – 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. Cumprido Desempenho - 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. Requisito - Já tratamos do requisito com servidores suficientes na seção de estimativa de capacidade. Cumprido Conclusão 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.