Recentemente, um cliente se aproximou de nossa equipe com uma necessidade específica e complexa: a criação de senhas robustas e diversificadas para seus usuários. A demanda incluiu requisitos como tamanho definido, quantidade mínima de números, letras maiúsculas e minúsculas, caracteres especiais e regras para iniciar a senha.

Em um mundo cada vez mais digitalizado, onde a segurança é vital, senhas fortes são essenciais para proteger informações sensíveis. No entanto, criar senhas complexas manualmente pode ser uma tarefa demorada e propensa a erros.

A Solução Inicial

Nossa primeira abordagem foi fornecer ao cliente uma função PL/SQL simples que poderia atender às suas necessidades básicas. A função foi projetada para ser executada diretamente no banco de dados Oracle, evitando a necessidade de pacotes especiais ou software adicional.

CREATE OR REPLACE FUNCTION GERAR_SENHA (
    p_tamanho          IN NUMBER,
    p_numeros          IN NUMBER,
    p_minusculas       IN NUMBER,
    p_maiusculas       IN NUMBER,
    p_iniciar_com      IN CHAR,
    p_tem_especial     IN CHAR,
    p_qtd_especial     IN NUMBER
) RETURN VARCHAR2 AS
    v_senha           VARCHAR2(100);
    v_caract_espec    VARCHAR2(10) := '!@#$%^&*()';
    v_alpha           VARCHAR2(52) := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    v_num             VARCHAR2(10) := '0123456789';
    v_count           NUMBER;
    v_pos             NUMBER;
BEGIN
    IF p_tamanho < (p_numeros + p_minusculas + p_maiusculas + p_qtd_especial) THEN
        RETURN 'Parâmetros inválidos.';
    END IF;

    IF p_iniciar_com = 'L' THEN
        v_senha := SUBSTR(v_alpha, DBMS_RANDOM.VALUE(1, 26), 1);
    ELSIF p_iniciar_com = 'N' THEN
        v_senha := SUBSTR(v_num, DBMS_RANDOM.VALUE(1, 10), 1);
    ELSIF p_iniciar_com = 'C' AND p_tem_especial = 'S' THEN
        v_senha := SUBSTR(v_caract_espec, DBMS_RANDOM.VALUE(1, 10), 1);
    ELSE
        RETURN 'Parâmetros inválidos.';
    END IF;

    FOR v_count IN 1 .. p_minusculas - 1 LOOP
        v_pos := LENGTH(v_senha) + 1;
        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_alpha, DBMS_RANDOM.VALUE(1, 26), 1);
    END LOOP;

    FOR v_count IN 1 .. p_maiusculas LOOP
        v_pos := LENGTH(v_senha) + 1;
        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_alpha, DBMS_RANDOM.VALUE(27, 52), 1);
    END LOOP;

    FOR v_count IN 1 .. p_numeros LOOP
        v_pos := LENGTH(v_senha) + 1;
        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_num, DBMS_RANDOM.VALUE(1, 10), 1);
    END LOOP;

    IF p_tem_especial = 'S' THEN
        FOR v_count IN 1 .. p_qtd_especial LOOP
            v_pos := LENGTH(v_senha) + 1;
            v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_caract_espec, DBMS_RANDOM.VALUE(1, 10), 1);
        END LOOP;
    END IF;

    WHILE LENGTH(v_senha) < p_tamanho LOOP
        v_pos := LENGTH(v_senha) + 1;
        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_alpha, DBMS_RANDOM.VALUE(1, 52), 1);
    END LOOP;

    RETURN v_senha;
END GERAR_SENHA;
/

O cliente ficou satisfeito com a solução, mas vimos uma oportunidade de aperfeiçoá-la.

Aprimorando a Solução

Decidimos ir além e melhorar a função, tornando-a mais flexível e segura. Introduzimos uma lógica adicional para embaralhar os caracteres da senha, aumentando a imprevisibilidade e a robustez da senha gerada.

CREATE OR REPLACE FUNCTION EMARALHAR (
        p_str_txt IN VARCHAR2
    ) RETURN VARCHAR2 AS
        v_length   NUMBER;
        v_output   VARCHAR2(100);
        v_random   NUMBER;
        v_aux      VARCHAR2(100);
    BEGIN
        v_length := LENGTH(p_str_txt);
        v_aux    := p_str_txt;
        FOR i IN 1 .. v_length LOOP
            v_random := DBMS_RANDOM.VALUE(1, LENGTH(p_str_txt));
            v_output := v_output || SUBSTR(p_str_txt, v_random, 1);
            v_aux := SUBSTR(p_str_txt, 1, v_random - 1) || SUBSTR(p_str_txt, v_random + 1);
        END LOOP;
        RETURN v_output;
    END EMARALHAR;

Além disso, encapsulamos as funções em uma package PL/SQL, separando a lógica de geração da lógica de embaralhamento e promovendo uma organização de código mais clara.

CREATE OR REPLACE PACKAGE SENHA_PKG AS
    FUNCTION GERAR_SENHA (
        p_tamanho          IN NUMBER,
        p_numeros          IN NUMBER,
        p_minusculas       IN NUMBER,
        p_maiusculas       IN NUMBER,
        p_iniciar_com      IN CHAR,
        p_tem_especial     IN CHAR,
        p_qtd_especial     IN NUMBER
    ) RETURN VARCHAR2;
END SENHA_PKG;
/

CREATE OR REPLACE PACKAGE BODY SENHA_PKG AS

    FUNCTION EMARALHAR (
        p_str_txt IN VARCHAR2
    ) RETURN VARCHAR2 AS
        v_length   NUMBER;
        v_output   VARCHAR2(100);
        v_random   NUMBER;
        v_aux      VARCHAR2(100);
    BEGIN
        v_length := LENGTH(p_str_txt);
        v_aux    := p_str_txt;
        FOR i IN 1 .. v_length LOOP
            v_random := DBMS_RANDOM.VALUE(1, LENGTH(p_str_txt));
            v_output := v_output || SUBSTR(p_str_txt, v_random, 1);
            v_aux := SUBSTR(p_str_txt, 1, v_random - 1) || SUBSTR(p_str_txt, v_random + 1);
        END LOOP;
        RETURN v_output;
    END EMARALHAR;

    FUNCTION GERAR_SENHA (
	    p_tamanho          IN NUMBER,
	    p_numeros          IN NUMBER,
	    p_minusculas       IN NUMBER,
	    p_maiusculas       IN NUMBER,
	    p_iniciar_com      IN CHAR,
	    p_tem_especial     IN CHAR,
	    p_qtd_especial     IN NUMBER
	) RETURN VARCHAR2 AS
	    v_senha           VARCHAR2(100);
	    v_caract_espec    VARCHAR2(10) := '!@#$%^&*()';
	    v_alpha           VARCHAR2(52) := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	    v_num             VARCHAR2(10) := '0123456789';
	    v_count           NUMBER;
	    v_pos             NUMBER;
	BEGIN
	    IF p_tamanho < (p_numeros + p_minusculas + p_maiusculas + p_qtd_especial) THEN
	        RETURN 'Parâmetros inválidos.';
	    END IF;

	    IF p_iniciar_com = 'L' THEN
	        v_senha := SUBSTR(v_alpha, DBMS_RANDOM.VALUE(1, 26), 1);
	    ELSIF p_iniciar_com = 'N' THEN
	        v_senha := SUBSTR(v_num, DBMS_RANDOM.VALUE(1, 10), 1);
	    ELSIF p_iniciar_com = 'C' AND p_tem_especial = 'S' THEN
	        v_senha := SUBSTR(v_caract_espec, DBMS_RANDOM.VALUE(1, 10), 1);
	    ELSE
	        RETURN 'Parâmetros inválidos.';
	    END IF;

	    FOR v_count IN 1 .. p_minusculas - 1 LOOP
	        v_pos := LENGTH(v_senha) + 1;
	        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_alpha, DBMS_RANDOM.VALUE(1, 26), 1);
	    END LOOP;

	    FOR v_count IN 1 .. p_maiusculas LOOP
	        v_pos := LENGTH(v_senha) + 1;
	        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_alpha, DBMS_RANDOM.VALUE(27, 52), 1);
	    END LOOP;

	    FOR v_count IN 1 .. p_numeros LOOP
	        v_pos := LENGTH(v_senha) + 1;
	        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_num, DBMS_RANDOM.VALUE(1, 10), 1);
	    END LOOP;

	    IF p_tem_especial = 'S' THEN
	        FOR v_count IN 1 .. p_qtd_especial LOOP
	            v_pos := LENGTH(v_senha) + 1;
	            v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_caract_espec, DBMS_RANDOM.VALUE(1, 10), 1);
	        END LOOP;
	    END IF;

	    WHILE LENGTH(v_senha) < p_tamanho LOOP
	        v_pos := LENGTH(v_senha) + 1;
	        v_senha := SUBSTR(v_senha, 1, v_pos - 1) || SUBSTR(v_alpha, DBMS_RANDOM.VALUE(1, 52), 1);
	    END LOOP;

	    v_senha := EMARALHAR(v_senha);

        RETURN v_senha;
	END GERAR_SENHA;


END SENHA_PKG;
/

Exemplo Prático

Aqui está um exemplo de como chamar a função GERAR_SENHA através da package:

SELECT SENHA_PKG.GERAR_SENHA(10, 2, 2, 2, 'L', 'S', 1) FROM DUAL;

Esta chamada geraria uma senha com 10 caracteres, incluindo pelo menos 2 números, 2 letras minúsculas, 2 letras maiúsculas, começando com uma letra e contendo pelo menos 1 caractere especial.

Utilidade na Vida do Banco de Dados

A solução aprimorada não é apenas útil para o cliente em questão, mas também tem amplas aplicações em muitos outros cenários. Bancos de dados em toda parte podem se beneficiar de uma função como essa para:

  • Gerar senhas para novos usuários de forma automatizada.
  • Redefinir senhas de maneira segura.
  • Integrar com sistemas existentes sem a necessidade de pacotes especiais.

Portabilidade

Embora a solução tenha sido escrita em PL/SQL para Oracle, o conceito pode ser facilmente traduzido para outros bancos de dados. Isso a torna uma solução atrativa para organizações que operam em diferentes ambientes de banco de dados.

Conclusão

O desafio trazido pelo cliente nos permitiu não apenas fornecer uma solução eficaz mas também aprimorar e expandir essa solução para um uso mais amplo.

A função aperfeiçoada demonstra como é possível atender a requisitos complexos de geração de senhas diretamente no banco de dados, sem depender de ferramentas externas, e é um excelente exemplo de como a flexibilidade e o poder da linguagem SQL podem ser usados para fornecer soluções eficientes, seguras e portáveis.

A capacidade de gerar senhas complexas dentro do próprio banco de dados, com parâmetros personalizáveis, é uma adição valiosa a qualquer sistema que lide com dados sensíveis e segurança do usuário. Nosso cliente agora possui uma ferramenta robusta que atende às suas necessidades, e esperamos que essa abordagem possa ser útil para outros também.

Sobre o autor

Pós graduado em Gestão de Projetos em Tecnologia da Informação pela UNIASSELVI.
Esposo e Pai, curto atividades ao ar livre (Bike, SUP, Natação, Caminhar, Brincar no campo)

Atua com Banco de Dados Oracle desde de 2007. Atualmente é DBA Senior na FLUIDATA Serviços em Banco de dados (www.fluidata.com.br)

Principais atividade Banco de dados:

Implementação, migração, gerenciamento e suporte a produtos Oracle (8i, 9i, 10g, 11g, 12c, 18c, 19c RAC), multiplataforma;
Implementação, migração, gerenciamento e suporte a produtos Microsoft SQL Server (2008 - 2019);
Implementação, migração, gerenciamento e suporte a produtos PostgreSQL (9.3 - 14);
Monitoramento de ambientes 24×7;
Backup e Recovery;
Performance e Tuning;
Alta disponibilidade (HA);
EM database/grid/cloud control;
Conversão de databases;
Standby database / Oracle Data Guard;

Certificações:

Oracle Cloud Infrastructure 2019 Certified Architect AssociateOracle Cloud Infrastructure 2019 Certified Architect Associate
Oracle Database 12c Administrator Certified ProfessionalOracle Database 12c Administrator Certified Professional
Exadata Database Machine Models X2-2 and X2-8 Technology Support SpecialistExadata Database Machine Models X2-2 and X2-8 Technology Support Specialist
Oracle Database 11g Support SpecialistOracle Database 11g Support Specialist
OCP 11g - Oracle Certified Professional AdministratorOCP 11g - Oracle Certified Professional Administrator
OPN Certified Specialist 10g - PartnerNetwork Certified SpecialistOPN Certified Specialist 10g - PartnerNetwork Certified Specialist
Oracle Database 10g Real Applications Clusters AdministratorCertified ExpertOracle Database 10g Real Applications Clusters AdministratorCertified Expert
Oracle Database 10g: Managing Oracle on Linux Certified ExpertOracle Database 10g: Managing Oracle on Linux Certified Expert
OCP 10g - Oracle Certified Professional AdministratorOCP 10g - Oracle Certified Professional Administrator

Principais atividades DEVOPS:

PHP
ASP.net
C#
Docker
Golang
C++
Delphi
Python
HTML5
JavaScript

Você também pode gostar: