O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

Cadastrando Usuários com Relativa Segurança

Iniciado por Corvo, 29/06/2020 às 21:01

29/06/2020 às 21:01 Última edição: 14/08/2020 às 19:11 por Corvo
Cadastrando Usuários com Relativa Segurança

Contexto
Oi, povo.
Continuo parcialmente exilado numa cabaninha no Tibete, mas tenho tentando manter contato com um mundo por um telefone-sem-fio (daqueles com latinhas) de setecentos metros montanha abaixo. Estive aprendendo com os monges sobre segurança da informação, achei a área muito legal e a melhor forma de fixar o conteúdo, além de treinar, é compartilhar. Não é um assunto normalmente tratado pelas bandas dos desenvolvedores independentes, mas deveria ser. Já tem gente invadindo geladeiras.
[close]



Neste artigo discutiremos sobre como gerenciar o registro de um usuário de forma relativamente segura. O objetivo é garantir que ele tenha uma senha digna e que ela seja salva sejá-lá-onde-precisar-ser sem muita dor de cabeça. Iremos usar a linguagem Python 3 para os códigos de exemplo. É interessante algum conhecimento mínimo em programação para prosseguir.




Criando o Usuário

Nossos usuários precisarão de uma classe. Podemos mantê-la o mais simples possível apenas para iniciar o código:

class User:

    def __init__(self, user: str, passwd: str) -> str:
        """ Create an User Object """
        self.username = user
        self.passwd = passwd




Gerenciando o Registro

Para testarmos nosso método, precisaremos de um gerenciador. Um objeto que fará as ações propriamente ditas:

# Tranqueiras que serão usadas em breve. Importe-as:
import hashlib
import secrets
import string

class Manager:

    def __init__(self):
        """ Initialize object and locals """
        self.users = [] # Lista onde os usuários serão salvos.
        # As quatro variáveis abaixo serão nossos meios de validar se uma senha é segura ou não.
        self.passwd_characteres_lower = string.ascii_lowercase
        self.passwd_characteres_upper = string.ascii_uppercase
        self.passwd_numbers = string.digits
        self.passwd_special = string.punctuation


A primeira coisa a ser verificada durante um registro é o usuário. Ele já existe ou o nome está disponível? Podemos descobrir com um método simples. Note que não exemplifiquei a função que pega a entrada do usuário, pulamos esta parte por se tratar de um simples input().

    def check_username(self, new_username: str) -> str:
        """ Check if is a valid Username """
        for user in self.users:
            if user.username == new_username:
                print("This username already exists.")
                return False
        return True


Se o usuário for válido, podemos prosseguir para a validação da senha. A sequencia de métodos à seguir verifica o número de caracteres, se há ou não letras maiúsculas e minúsculas, digitos e caracteres especiais. Para cada elemento destes, temos uma quantidade específica de caracteres. Tenha em mente que segurança é proporcionalmente inversa à usabilidade, ao menos por enquanto. Tome cuidado para não exigir de um usuário a senha nU*(HN*IN2kjbY7*bdiDBp*(0(Jn@@@@@@@@@----23232kdjsma para acessar uma calculadora.

def check_passwd(self, passwd: str) -> str:
        """ Check if is a valid password """
        while True:
            # Check Size
            if len(passwd) < 14:
                print("This password is too short.")
                break            

            # Check Ascii Lowercase Letters
            counter = 0
            for i in passwd:
                if i in self.passwd_characteres_lower:
                    counter += 1
            if counter < 3:
                print("Your password need at last tree (3) lowercase characteres.")
                break

            # Check Ascii Uppercase Letters
            counter = 0
            for i in passwd:
                if i in self.passwd_characteres_upper:
                    counter += 1
            if counter < 3:
                print("Your password need at last tree (3) uppercase characteres.")
                break

            # Check Digits
            counter = 0
            for i in passwd:
                if i in self.passwd_numbers:
                    counter += 1
            if counter < 6:
                print("Your password need at last six (6) digits.")
                break

            # Check Special Characteres
            counter = 0
            for i in passwd:
                if i in self.passwd_special:
                    counter += 1
            if counter < 2:
                print("Your password need at last two (2) special characteres.")
                break

            # The password has passed!
            return True


Se a senha passou por todo este processo, ela é segura. Certo? Não necessariamente. Nós não nos certificamos de que a senha não tenha padrões óbvios como 123456, abcdef, QWERT, nem se contém palavras como senha ou coisas do tipo. Isso pode nos tomar algum tempo. Aqui, iremos substituir esta etapa acrescentando outro atributo ao usuário: o salt. Literalmente, jogaremos uma pitada na senha para fortalecer o conjunto. Nossa classe de usuário ficará assim:

class User:

    def __init__(self, user: str, passwd: str, salt: str) -> str:
        """ Create an User Object """
        self.username = user
        self.passwd = passwd
        self.salt = salt


Por fim, adicionados outro método ao nosso gerenciador. Ele usa o módulo secrets para gerar trechos aleatórios, nossos salts, que depois são incluídos no final da senha do usuário. Por exemplo, se a senha digitada for 123, ela será passada para o próximo processamento como 12326Z1xpHZUTD-lUofbT-b9g. O salt gerado deve ser salvo na conta, pois toda vez que o usuário tentar acessar seu perfil, o mesmo salt deve ser adicionado à senha inserida.




Finalizando

Certo, estamos quase terminando. Quase porque não adianta passar por toda essa labuta se, no final, a senha for salva no servidor da seguinte forma:

user: Gibson Willian
password: 12326Z1xpHZUTD-lUofbT-b9g


A última etapa é passar o resultado senha+salt por um algorítimo de hash. Resumindo bastante, uma hash é... Bem, é o que sai de um liquidificador sempre que você joga os mesmos ingredientes na mesma quantidade e pelo mesmo tempo. Mais ou menos. Para que nós dois aprendamos mais sobre elas, vale a recomendação.

    def protect_passwd(self, passwd: str) -> str:
        """ Encrypt the password before save it. """
        salt = secrets.token_urlsafe(32)
        encripted_passwd = hashlib.sha256((passwd + salt).encode()).hexdigest()
        return (encripted_passwd, salt)


Veja abaixo o que o código gera como os dados de um usuário. (Senha mantida visível por questões óbvias):

Type your username: Gibson Willian
Type your password: @123456asdfgQWERT@

User name: Gibson Willian
Saved password: 872282732817f394f0a82e27cd2fc92b7769ecbced7fc3ec217f8ec0b33fcc76
This-user salt: dt98sQo6VBmKKTKg5TtfarTU9kAXljAhfcaE7yxUwGs


Ficamos por aqui. O código completo, inclusas as funções de inseção para testes está aqui. É só executar. :D

Exercícios:

1. Crie uma função de acesso, permitindo que usuários cadastrados previamente entrem com suas respectivas credenciais.



Referências de Conteúdo
Se você não programa, o curso Python - Fundamentos para Análise de Dados da DataScience garante que você comece bem. Cobre desde os primeiros passos na lógica até introduções à big data, deep learning e demais tecnologias modernas com nome engraçado, mas que no fundo são quase a mesma coisa. Só não fique preso à uma linguagem por ser ela fácil. Eu fiquei e estou me lascando pra entender C e os malditos pointers. Tudo é um pointer de um pointer de um pointer nesse troço.

Já pra começar pela parte da segurança, o curso da Solyd é um bom primeiro passo. Você vai aprender o que é estritamente necessário pra começar, então não pense que irá encontrar segredos profundos de bruxaria por lá. Mas eu recomendo justamente por ser mais simples, menos formal. Para não assustar quem está na ponta da fila. Dica extra: dá pra pegar por um terço do preço em promoções.

Os cursos da Desec eu ainda estou fazendo, mas já posso recomendar. O conteúdo é bem mais aprofundado, a prática é mais organizada e os tópicos divididos em aulas menores, fáceis de consultar posteriormente. São relativamente caros, mas não me arrependo. Agora, se a sua pessoa quiser ir um pouco mais além: para análise forense, não é incomum encontrar o curso da Basis Tech de graça, sobre a ferramenta deles que é usada por agências de todo canto: Autopsy. Estes caras aqui também podem te ajudar a tomar um rumo na vida.

Enfim, o conteúdo é muito variado. Pra criptografia e tecnologias ou técnicas mais específicas eu recomendo o de sempre: livros. Autores famosos como Mitnick, Dafydd Sttutard para a coisa em si. Outras personas de áreas externas, mas que podem te ajudar aqui como Paul Ekman, Joe Navarro, Maria Konnikova, Amy Herman... Enfim. É o caso de identificar qualquer coisa que possa ser útil e como.
[close]