Criptografia em AdvPL – Parte 10

Introdução

No post anterior, vimos em mais detalhes o objetivo e uso das chaves públicas, e como funciona um Handshake de conexão segura para HTTPS. Agora, vamos ver como gerar um certificado digital a partir de outro certificado, usando o certificado “pai” para autenticar o certificado “filho”, e usar isso no nosso exemplo de HTTPS 😀

Posts anteriores

Lembrando do primeiro teste com HTTPS

No Post 06 tem a receita de bolo pra gerar um certificado auto-assinado e usá-lo no TOTVS Application Server para prover acesso via HTTPS. Em resumo, trata-se de um certificado auto-assinado com extensões v3, para ser usado no servidor HTTPS em um determinado host, e para o navegador aceitar o certificado, ele precisava ser instalado na máquina cliente como um Trusted Root Certificate.

Certificados com cadeia de autenticação

Agora, vamos fazer um mecanismo um pouco mais elegante: Criar um certificado raiz auto-assinado, e criar um outro certificado para o HTTPS, com todos os dados necessários, porém assinado pelo primeiro certificado. E isso permite eu praticamente fazer o papel de uma autoridade certificadora — não oficial, claro.

Imagine que eu vou fazer o papel fictício de Autoridade Certificadora, e você quer criar um site seu, usando um certificado seu, mas quer que ele seja autenticado pelo meu certificado. Eu, como autoridade certificadora fictícia, tenho um certificado auto-assinado que eu uso como “raiz”, a base de tudo, com uma chave privada minha atrelada a este certificado.

Então, primeiro você cria a sua chave privada para ser usada pelo seu certificado. Porém, você não vai criar o certificado propriamente dito, você vai criar uma CSR (Certificate Signing Request), ou requisição de assinatura de certificado, com tudo o que você quer no seu certificado, e vai mandar ela para eu assinar com o meu certificado e com a minha chave. Eu vou criar o seu certificado para você, usando os dados que você forneceu na requisição de assinatura, e vou assinar o seu certificado com o meu.

Repare que eu tenho uma chave privada do meu certificado, e você vai usar a sua chave privada no seu certificado, mas em nenhum momento nem eu e nem você podemos tre acesso as chaves privadas um do outro. Neste processo as chaves públicas são intrinsecamente utilizadas: Quando eu receber a sua requisição de assinatura, a requisição em si traz junto a sua chave pública embutida, e todos os dados que você quer no seu certificado. Eu crio e assino o seu certificado, para que ele possa ser autenticado pelo meu certificado, mas o seu certificado ainda assim vai usar a sua chave privada no seu ambiente.

Quando você colocar o seu site no ar, você vai usar o seu certificado e a sua chave privada nas configurações do HTTPS, porém você não vai precisar pedir para os seus clientes — que vão acessar o seu site — instalar o seu certificado na maquina deles, você pede para eles instalarem o meu certificado — que assinou o seu — como Trusted Root Certificate. 😀 Assim, a máquina que tiver o meu certificado raiz não vai ter a minha chave privada, e o meu certificado será usado para verificar a assinatura do seu certificado quando o cliente acessar o seu site 😀

Fazendo a mágica

Eu, atuando como Autoridade Certificadora, crio a minha chave privada e o meu certificado auto-assinado:

-- Criando chave privada protegida por senha 
openssl genrsa -des3 -out rootCA.key 4096

-- Criando o meu certificado raiz para ser uma "autoridade certificadora"
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt 

O primeiro comando vai perguntar a senha para uso da chave privada, e na criação do meu certificado raiz eu coloco informações que me identificam.

Agora você vai criar a sua chave privada e uma requisição de assinatura para o seu certificado:

-- Voce cria a sua chave privada
openssl genrsa -out mydomain.com.key 2048

-- e cria uma requisição de assinatura
openssl req -new -key mydomain.com.key -out mydomain.com.csr -subj "/C=BR/ST=SP/L=Sao Paulo/O=Testes INC/CN=mydomain.com" 

A sua requisição de assinatura vai estar gravada no arquivo “mydomain.com.csr“, e você manda esse aquivo para eu assinar com o meu certificado. Eu vou assinar seu certificado com o seguinte comando:

openssl x509 -req -in mydomain.com.csr -extfile v3.ext -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt

Para assinar o seu certificado, eu tive que criar um arquivo a mais, no exemplo acima chamado de “v3.ext”, onde eu vou colocar algumas extensões no seu certificado.

basicConstraints = CA:FALSE
keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectKeyIdentifier = hash
subjectAltName=DNS:mydomain.com

No final das contas, o seu certificado vai ser gerado no arquivo “mydomain.com.crt“, e eu mando esse arquivo pra você, e mando também o meu certificado “rootCA.crt“.

Agora você tem a sua chave privada “mydomain.com.key”  e o seu certificado “mydomain.com.crt“, e você configura o seu servidor HTTPS para usá-los.

[sslconfigure]
CertificateServer=c:\Protheus12LG\certificates\mydomain.com.crt
KeyServer=c:\Protheus12LG\certificates\mydomain.com.key

E, você ou qualquer outra pessoa que acesse o seu site, deve apenas instalar o meu certificado na máquina cliente como “Trusted Root Certificate“. Dessa forma, quando um navegador abrir o seu site, ele vai encontrar o seu certificado, e para validar a relação de confiança desse certificado, ele procura um certificado raiz confiável, e encontra o meu certificado — que é capaz de dizer que o seu certificado foi assinado por mim 😀

Se, amanhã você colocar outro site no ar, você repete o processo de criação de chaves e requisição de assinatura, e eu crio e assino o seu novo certificado, e todas as pessoas que já instalaram o meu certificado nas máquinas delas para acessar o seu site, não precisam mais instalar nada, pois o meu certificado raiz é capaz de autenticar qualquer certificado que eu tenha assinado com ele 😀

Estendendo a cadeia de autenticação ou confiança

Por hora a cadeia de autenticação desse exemplo possui apenas o certificado raiz, e cada certificado assinado por ela confia no raiz. Se, ao invés de você me pedir para assinar um certificado de uso final, você crie o seu certificado raiz e eu assine esse certificado, você mesmo pode emitir certificados para terceiros, assinados com o seu certificado raiz. Com isso, quando um navegador usar um certificado que você emitiu, ele vai procurar o seu certificado raiz — que não necessariamente precisa ser um “Trusted Root”, mas sim um “Trusted CA” — e quando ele encontrar o seu certificado raiz, ele verifica que ele foi emitido por mim, e confia nele desde que o meu certificado raiz seja um “Trusted Root” 😀

Eu sei, logo de cara é um pouco complicado, mas esse mecanismo — quando bem configurado e utilizado — provê um mecanismo de confiança muito seguro. Vamos ver agora alguns exemplos do mundo real.

Assinatura digital de aplicativos

Quando você vai instalar um programa qualquer,  o sistema operacional da sua máquina verifica se o seu programa tem uma assinatura digital que indica quem é o fornecedor desse programa. A cadeia de autenticação é praticamente a mesma, porém você tem um tipo diferente de certificado, com outras propriedades e extensões. Na instalação do programa, ao verificar o certificado usado para a assinatura, caso a assinatura não possa ser verificada, o sistema operacional pergunta se você confia nessa assinatura, e você aceita o risco de instalar o programa. E, se você confia naquela assinatura, você pode ainda declarar que “sempre confia” naquela assinatura, e quando você instalar outro programa assinado com este certificado, o sistema operacional não vai perguntar novamente se você confia nele, e vai deixar o programa ser executado.

Agora, já pensou se alguém consegue assinar um aplicativo malicioso, com um vírus ou um Trojan Horse, copiando a assinatura da Microsoft ? Ou da Symantec ? Se a assinatura for determinada erroneamente como confiável, o estrago é inimaginável e transparente, o programa faz o que quiser com a sua maquina !!! Por isso a infraestrutura de segurança é desenhada para não ser quebrada, senão a “vaca vai pro brejo” !!!!

Conclusão

Já vimos bastante coisa até o momento, mas ainda têm bastante a ser visto. Toda essa introdução com os respectivos exemplos serve para a gente entender o tamanho do mecanismo e seus componentes. A partir de agora, todas as demais camadas e mecanismos são baseados em tudo o que foi explicado até aqui, isso serve de “base” para tudo o que ainda vamos ver pela frente !!!

Agradeço novamente pela audiência, e lhes desejo TERABYTES DE SUCESSO !!! 

Referências

 

 

Criptografia em AdvPL – Parte 08

Introdução

No post anterior, vimos alguns pacotes de rede e requisições feitas com HTTP e com HTTPS, e um FAQ com algumas perguntas intrigantes e respectivas respostas. Agora, vamos aproveitar que já temos um certificado digital de testes e habilitar a conexão segura entre o TOTVS SmartClient e o TOTVS Application Server ?!

Posts anteriores

Conexão SmartClient com SSL

A seção de configuração [sslconfigure] do TOTVS Application Server foi criada para definir as configurações default para uso de criptografia na infraestrutura do servidor de aplicação, e auxiliar na portabilidade de funções nativas da linguagem para suporte a protocolos seguros. Ela possui diversas chaves de configuração, o que vimos até agora no post 06 foi apenas configurar o uso de um certificado digital e uma chave criptográfica em modo “servidor”, utilizada pela engine de servidor WEB nativa da plataforma para publicar um site ou serviço acessado por HTTPS.

Porém, também podemos habilitar uma conexão segura e criptografada entre o SmartClient e o Application Server, e quando fazemos isso, o certificado configurado como “ServerCertificate” e a sua chave correspondente serão usados para permitir essa implementação.

Configuração DRIVERS

No arquivo de configuração do TOTVS Application Server (appserver.ini), existe uma seção chamada [drivers], responsável por indicar a seção TCP para especificar a porta de conexão a ser usada pelo TOTVS SmartClient, Monitor, IDE/TDS e afins. Para habilitar a conexão segura para o SmartClient, acrescentamos as chaves em negrito:

[drivers]
active=tcp
secure=ssl

[tcp]
type=tcpip
port=12010

[ssl]
type=tcpip
port=13010

Pronto, com isso o Application Server vai usar a porta 13010 para atender a conexões seguras de SmartClient. Lembre-se que o certificado digital e a chave deve estar configurados na seção SSLConfigure, senão o Application Server não inicia…

[sslconfigure]
CertificateServer=C:\Protheus12LG\certificates\note-juliow-ssd.cer
KeyServer=C:\Protheus12LG\certificates\note-juliow-ssd.key

Para as conexões do SmartClient, pode ser usado o mesmo certificado que foi gerado para o HTTPS, inclusive pode até ser um certificado mais “simples”, sem as extensões obrigatórias que um navegador Web exige.

E uma vez feito isso e reiniciado o Application Server, você não precisa fazer nada nas configurações do SmartClient. O Application Server continua aceitando as conexões do SmartClient na porta da seção TCP, porém ao receber uma conexão de SmartClient na porta não segura, o próprio Application Server sabe que existe uma porta segura de conexão, então ele devolve para o SmartClient uma mensagem de reconexão segura, informando a porta configurada na seção SSL 😀

Quando o Application Server com estas configurações for iniciado, repare que no log de console devem aparecer algumas novas mensagens:

Secure Application Server.

[ERROR][STORE] Certificates loaded from [C:\Protheus12LG\certificates\note-juliow-ssd.cer].
[INFO ][SERVER] [Thread 11048] Secure Server started on port 13010.

The callback state information is active.
The PassPhrase is supplied.

*** Existe uma mensagem informando “ERROR” no log acima, que provavelmente está equivocada, deveria ser “INFO” — pois o certificado foi carregado com sucesso.

Configurando o SmartClient para conectar direto na porta segura

Embora apenas a configuração do Application Server já resolve a questão de conexão segura, existe uma forma de você configurar o SmartClient para conectar direto na porta segura, assim o SmartClient não precisa conectar na porta não segura para receber o número da porta segura e reconectar. Basta editar o arquivo de configuração do SmartClient (smartclient.ini), e criar uma nova seção de configuração de conexão, informando na seção a porta segura, e acrescentando a configuração SecureConnection=1, por exemplo:

[drivers]
active=tcp

[tcp]
server=note-juliow-ssd
port=12010

[ssltest]
server=note-juliow-ssd
port=13010
SecureConnection=1

Ao executar o SmartClient, basta trocar a conexão tcp para ssltest, e ele conectará direto na porta de conexão segura especificada, veja imagem abaixo:

Smartclient_ssl

Informações adicionais de depuração de SSL

Caso exista algum problema com uso de certificado ou criptografia no TOTVS Application Server, em qualquer funcionalidade que use chaves criptográficas e certificados e afins, é possível colocar na seção [sslconfigure] a chave verbose=1 . Com isso qualquer processo que envolver a camada de segurança e criptografia do Application Server vai gerar mensagens adicionais de diagnóstico no log de console do servidor. Vale lembrar que isso deve ser ligado apenas para fins de depuração, pois ela pode gerar muito conteúdo adicional e os detalhes gerados são apenas úteis para levantar mais informações sobre um problema relacionado a este mecanismo.

A seção [sslconfigure] possui muito mais chaves, se você está curioso em saber todas elas, veja os links de referência no final do post para a documentação oficial do TDN. Cada post explorando um novo recurso ou funcionalidade vai abordar sob demanda as chaves necessárias e explicando mais detalhes do seu funcionamento 😀

Conclusão

Com o que vimos até agora, já foi possível testar conexões seguras de HTTPS e SmartClient. No próximo post, vamos ver um pouco mais sobre os certificados digitais, e onde as funções do AdvPL se encaixam no uso desses certificados para diversos fins.

Agradeço novamente pela audiência, e desejo a todos TERABYTES DE SUCESSO !!! 

Referências

 

Criptografia em AdvPL – Parte 07

Introdução

No post anterior, configuramos um TOTVS Application Server como servidor HTTP e HTTPS, usando um certificado digital criado na raça usando a OpenSSL, do tipo “auto-assinado”, sem uma Autoridade Certificadora. Agora, aproveitando que temos um ambiente com um site que atende conexões não-seguras e seguras, vamos ver o que passa por dentro da camada de rede usando esses dois tipos de conexão.

Posts anteriores

Usando um analisador de pacotes de rede

Como temos agora um servidor configurado para conexões HTTP (Porta TCP 80) e HTTPS (Porta TCP 443), vamos ver como é possível “interceptar” a comunicação entre o navegador e o servidor HTTP usando um programa “espião de pacotes” — também chamados de Sniffer ou Network Packets Analyzer.

No caso, vou usar um analisador de rede chamado Wireshark — OpenSource, já tem Builds prontas para Windows e Linux, disponíveis no link https://www.wireshark.org/download.html — A instalação é tão simples quanto Next->I Agree->Next->Next->Next->Finish. Não vou entrar em mais detalhes desse recurso no momento, não é o foco desse post, apenas vou mostrar como o conteúdo transferido entre o servidor HTTP e o navegador pode ser visto — este é o pacote de resposta do servidor com a página HTML, usando uma conexão HTTP (não segura):

wireshark_http.png

A requisição que a imagem acima mostra é a resposta do servidor HTTP quando eu abri o navegador e pedi a página http://note-juliow-ssd.index.html. Se a gente ver o quando de informações o navegador enviou para o servidor quando pediu essa página, o Browser manda muitas informações:

GET /index.html HTTP/1.1
Host: note-juliow-ssd
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,sv;q=0.5

As informações acima foram enviadas pelo Chrome ao servidor HTTP do Protheus quando eu pedi um “Refresh” da página Index.html.

Interceptando os pacotes de uma conexão segura

Bem, meu chapa, o analisador de pacotes de rede intercepta tudo, inclusive uma conexão segura … Você consegue ver todas as etapas de HandShake e trocas de cifras e certificados entre as partes envolvidas, e depois os pacotes de dados … mas não adianta NADA, mesmo que você intercepte TODOS os pacotes … os tipos de informações trocadas entre o navegador e o servidor também estão criptografadas, o máximo que você pode fazer é olhar para os pacotes de dados e chorar … por que somente o servidor e o navegador sabem o que tem dentro 😀

https_application_data

Por exemplo, na imagem acima vemos um dos pacotes de dados trocados entre o navegador e o servidor HTTPS … não dá pra saber se foi uma pergunta ou uma resposta, ou o que isso quer dizer … e mesmo que você consiga fazer um ataque conhecido como “Man In The Middle”, isto é, fazer esta conexão passar por um “Tunnel TCP” dentro de uma aplicação sua, se você tentar mexer em um bit desse conteúdo, a decodificação da mensagem falha e a requisição sequer será processada, a camada de segurança que encapsula a conexão retorna um erro, e tchau.

Todo esse mecanismo tem como base a chave criptográfica privada armazenada no arquivo  “note-juliow-ssd.key”, em formato codificado BASE64. Como esta chave é única, e ainda foi criada sem senha, se eu usar ela para uma comunicação segura de uma aplicação de comunicação oficial, eu já comecei errado, por várias razões.

  • Chave privada sem proteção de senha
  • Certificado emitido sem uma Autoridade Certificadora

Se alguém coloca a mão nessa chave privada, desprotegida, e ela é usada para trocas de dados importantes, é possível gerar um outro certificado com outros dados baseado nesta chave, e usá-lo por exemplo para subir um servidor que finge ser “eu” em outro endereço na internet. e usando outros artifícios, fazer um “Tunnel TCP” entre o cliente e o meu servidor verdadeiro, capaz de ver o conteúdo descriptografado das mensagens — inclusive eu pretendo fazer esse teste mais pra frente.

E, se eu perder a minha chave privada, ou ela está protegida por senha e eu esquecer a senha … e eu usei essa chave para criptografar documentos, arquivos, imagens, qualquer coisa, esquece. Sem ela nem eu consigo decodificar as informações. Por isso que foram criados até dispositivos de hardware — como o HSM — para o acesso e uso controlado e restrito destas chaves. A segurança dessas chaves é criada de tal forma, que é possível saber que a senha está errada, mas não é possível determinar a senha certa.

F.A.Q.

P: O certificado foi gerado para o host  “note-juliow-ssd”, o que acontece se eu tentar acessar o HTTPS usando por exemplo https://localhost/index.html ou o IP da máquina ?

R: Como o certificado possui uma definição de DNS usando “note-automan-ssd“, se eu usar outro hostname para abrir o site, o Navegador avisa que tem algo errado — mais precisamente o erro “NET::ERR_CERT_COMMON_NAME_INVALID”

https_failed

P: Tentei abrir o endereço certinho no Mozzila, mesmo depois de importar o certificado. Por que não funcionou ?

mozilla_failedR: Repare na mensagem de erro :  MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT — O navegador Mozilla é mais restritivo, mesmo eu importando o certificado, ele avisa que trata-se de um certificado auto-assinado, mas permite continuar desde que você clique no link “Aceite o risco e continue” 😛 

P: Se eu entrar no site do Google por exemplo, digitando http://www.google.com , aparece um cadeado ?! Como ?! Eu não entrei no site com uma conexão não-segura ???

R: Sim, você entrou, o site do Google, Facebook e muitos outros possuem o acesso por HTTP (Porta 80 sem criptografia) e HTTPS (Porta 443 com criptografia). Mas, quando você entra pela conexão não segura, o site atende a conexão com HTTP, e retorna uma instrução de redirecionamento para o navegador solicitar novamente a mesma URL, porém mas usando a conexão segura. Veja por exemplo o pacote retornado pelo Google quando eu abri uma URL de pesquisa usando http://www.google.com.br/search?q=siga0984

HTTP/1.1 307 Internal Redirect
Location: https://www.google.com.br/search?q=siga0984
Non-Authoritative-Reason: HSTS

P: Como uma conexão HTTPS de um site qualquer é segura, se eu não precisei instalar na minha máquina nenhum certificado para ela funcionar ?!

R: Uma conexão segura de HTTPS exige que pelo menos uma das extremidades tenha um certificado e uma chave. No caso, os sites “abertos” como Facebook , Google e a grande maioria, usam um certificado oficial apenas no servidor, para garantir a identidade do servidor, e a chave de criptografia para codificar a conexão. O navegador acessa o certificado do servidor no “HandShake“, e com isso pode confirmar que o site que você acessou é “oficial”. Alguns sites, como os da Receita Federal, podem exigir uma autenticação por cerificado digital, como um eCPF ou eCNPJ por exemplo, que você vai usar na sua máquina, para o site conseguir determinar quem é você 😀 Não é apenas uma conexão segura e codificada, mas também permite ao servidor saber mediante o seu certificado digital quem é você, e que “você é mesmo você” 😀

Conclusão

O que vimos nestes dois últimos posts foi apenas o be-a-bá de como subir um site de testes com HTTPS. Nos próximos posts, vamos desbravar mais possibilidades desse universo.

Espero que vocês aproveitem bem e usem com sabedoria e responsabilidade estes conhecimentos, e desejo a todos como sempre TERABYTES DE SUCESSO !!! 

Referências

 

Criptografia em AdvPL – Parte 04

Introdução

Nos posts anteriores, abrimos a caixa de Pandora da criptografia, e os três primeiros posts vimos uma introdução ao assunto e tudo o que temos em matéria de HASH Criptográfico em AdvPL. Agora, vamos entrar no mundo das conexões seguras, chaves criptográficas e certificados digitais 😀

Posts anteriores

Glossário – Introdução de terminologias

Como são muitas terminologias novas, vou colocar aqui no começo algumas descrições breves sobre algumas palavrinhas novas que vamos ver muito daqui pra frente 😀

Chave criptográfica — Uma chave criptográfica é uma parte da informação que permite codificar (ou cifrar) um texto em algo incompreensível, que somente pode ser decodificado por quem também têm esta chave. A criptografia assimétrica baseia-se em pelo menos um par de chaves — a chave privada, que deve ser de acesso único da pessoa ou entidade proprietária da chave, e a chave pública, gerada a partir da chave privada usando um método que não torna possível descobrir uma através da outra.

Criptografia assimétrica — Mais conhecida por criptografia de chave pública e privada, oferece um método seguro de troca de mensagens entre as partes envolvidas na troca de mensagens e documentos criptografados ou assinados com um certificado digital. É necessário um par de chaves para codificar e decodificar uma informação.

Criptografia simétrica – Método criptográfico que utiliza apenas uma chave criptográfica para codificar e decodificar uma informação.

Certificado Digital — Trata-se de um arquivo eletrônico que serve como identidade virtual para uma pessoa física ou jurídica, e por ele pode se fazer transações online com garantia de autenticidade e com toda proteção das informações trocadas. Ela contém alguns dados de identificação, uma chave criptográfica púbica para identificá-lo em comunicações seguras e assinaturas digitais.

Assinatura Digital — Processo realizado sobre um documento, envolvendo HASH e criptografia assimétrica, para garantir que um documento não foi alterado ou adulterado após assinado, e garantindo em caráter irrevogável que a assinatura digital pertence ao emissor do documento, de forma autêntica e irretratável. De forma resumida, um HASH do documento é gerado e criptografado com a chave privada do emissor, e esse conteúdo passa a fazer parte daquele documento. A autenticidade do documento e validade da assinatura pode ser verificada por outra entidade que possua a chave pública do emissor, descriptografando o HASH que está no documento usando a chave pública do emissor, e recalculando o HASH do documento para ver se os valores são idênticos.

Conexão Segura (SSL e/ou TLS) — Trata-se de uma especificação de protocolo de conexão segura, criada para prover privacidade e integridade das informações trocadas entre as duas pontas da conexão. É uma especificação extensa e bem flexível, que internamente usa chaves criptográficas geradas dinamicamente, envolvendo pelo menos a autenticidade do certificado digital usado pelo servidor, mas também pode envolver a autenticação de ambas as partes através de uma troca de certificados e de chaves públicas entre as partes envolvidas.

OpenSSL — Trata-se de um projeto Open Source criado para prover ferramentas e bibliotecas de funções para criar e manipular certificados digitais, funções criptográficas e implementação de conexões seguras SSL/TLS para Clientes e Servidores. Vamos usá-la em breve, inclusive…

RSA – Nome do principal sistema / especificação de criptografia e assinatura digital, baseado em chave pública. Criado em 1978, é um dos mecanismos de criptografia mais usados no mundo, e considerado um dos mais seguros.

AES – Acrônimo de Advanced Encryption Standard, é o nome da especificação de um algoritmo de criptografia simétrico de dados eletrônicos estabelecida pelo Instituto Nacional de Padrões e Tecnologia (NIST) dos EUA em 2001. Ela substitui o DES — Data Encryption Standard — publicado em 1977

DES e 3DESData Encryption Standard e Triple Data Encryption Algorithm , respectivamente, são algoritmos de criptografia de 56 bits e 168 bits (***) de tamanho de chave, atualmente considerados inseguros devido ao tamanho curto das chaves empregadas, foram substituídos pelo AES.  

(***) Embora o 3DES tenha uma chave de 168 bits, ele é composto por três chaves de 56 bits, onde a primeira é igual a terceira, garantindo uma segurança efetiva de apenas 112 bits.

X.509 — Trata-se da especificação do formato de um certificado digital de chave pública. A especificação possui até o momento três versões, sendo que a versão 3 está em uso e atende a múltiplas necessidades com segurança a mais de 20 anos.

PKCS 12# — Formato de arquivo para armazenamento de múltiplos objetos criptográficos — chaves, certificados, etc — em um único arquivo. O Windows usa esta especificação em arquivos com extensão .PFX — Os certificados digitais X.509 podem ser gravados em arquivos com outros formatos e extensões, como por exemplo .pem , .cer , .per, .der , .p12, … O formato PEM é codificado em BASE64 e pode ser aberto para visualização em um editor de textos comum. Os formatos de arquivos são divididos em dois tipos : Container (pfx,pks12,pkcs7) e Encoding (pem,der,cert).

Só pelo número de termos e conceitos, percebe-se que o assunto é extenso … mas se abordarmos ele por partes — algumas partes, um monte de partes — veremos que todas se encaixam, e que o monstro não é tão feio assim 😀

Onde tudo isso é utilizado ?

Conexões seguras usando SSL/TLS são usadas em diversos protocolos, como HTTPS (Conexões WEB seguras — sites de e-commerce, bancos, etc), protocolos de acesso a e-mails por conexão segura (SMTP, POP3, IMAP). Assinaturas digitais são usadas em documentos como NFE (Nota Fiscal Eletrônica), e-mails com certificado pessoal, eCPF e eCNPJ para acesso e operações com as ferramentas e portais da Secretaria da Fazenda, o leque é muito grande.

Como isso é utilizado ?

Aí sim, a resposta é maior ainda. Existem tipos de certificados digitais para finalidades diferentes, entidades e órgãos certificados para a emissão de certificados, conjuntos de certificados auxiliares para validação e autenticação dos certificados emitidos, formas e padrões para a assinatura digital de vários tipos de documentos, conexões seguras com ou sem autenticação do cliente, com parâmetros e tipos de chaves diferenciados, cada utilização tem a sua receita de bolo que pode usar ou não boa parte desse embrolho 😛

Para não dar nó nem na minha cabeça e nem na de vocês, eu acho interessante começar com os testes práticos em pequenas aplicações, demonstrando os comportamentos apresentados pelos componentes envolvidos para cada caso de uso. Assim, fica mais fácil entender o que cada caso têm em comum, e como as funções do AdvPL e as configurações do TOTVS Application Server permitem usar tudo isso, além de descrever o que exatamente e como ele suporta cada recurso para cada caso .

O material de pesquisa na Internet é muito amplo e completo, ao longo dos posts dessa série eu me baseio em muito material, todos os posts são acompanhados dos links de referência de onde eu obtive as informações, utilize-os e não se limite as fontes que eu usei, pesquise outras fontes para obter mais detalhes 😀

Conclusão

Por hora eu acho que já tem bastante coisa pra digerir e assimilar, os termos usados aqui serão repetidos com frequência nos próximos posts, não se acanhe em ler esta página quantas vezes forem necessárias para fixar estas terminologias 😀

Espero que este conteúdo lhe seja útil, em caso de dúvidas ou sugestões, escreva um comentário, e novamente desejo a todos TERABYTES DE SUCESSO !!!

Referências

 

Criptografia em AdvPL – Parte 03

Introdução

Nos post anterior (Criptografia em AdvPL – Parte 02), vimos com mais propriedades os hashes criptográficos MD5 e SHA1, e as funções AdvPL correspondentes. Agora, vamos ver todas as demais funções de hash disponíveis no AdvPL !!!

Formatos suportados no AdvPL

As funções publicadas no AdvPL para hash criptográfico permitem o cálculo de hash usando os seguintes formatos / algoritmos:

  • MD5
  • RIPEMD160
  • SHA1
  • SHA224
  • SHA256
  • SHA384
  • SHA512

A maioria das gerações de hash possuem funções próprias, enquanto outras usam uma função de encapsulamento para gerar vários tipos de hash criptográfico. Vamos começar pela função que permite gerar todos estes hashes.

Função AdvPL EVPDigest()

Esta função permite gerar todos os hashes acima a partir de uma string em AdvPL, e um segundo parâmetro numérico para indicar qual o algoritmo para a geração do hash deve ser utilizado. A documentação dela na TDN está disponível no link http://tdn.totvs.com/display/tec/EVPDigest

A diferença de comportamento dela para as demais já vistas anteriormente, é que — por hora — seu retorno é uma nova string binária com o hash correspondente, e não uma string com o hash em hexadecimal. Mas isso não é problema, podemos converter o resultado para hexadecimal de forma muito simples. Vamos ao exemplo:

User Function Hash2()
Local cInfo := 'Hello AdvPL'
Local nI

conout('String ......... ['+cInfo+']')

conout('MD5 ............ ['+Str2Hex(EVPDigest(cInfo,1))+']')
conout('RIPEMD160 ...... ['+Str2Hex(EVPDigest(cInfo,2))+']')
conout('SHA1 ........... ['+Str2Hex(EVPDigest(cInfo,3))+']')
conout('SHA224 ......... ['+Str2Hex(EVPDigest(cInfo,4))+']')
conout('SHA256 ......... ['+Str2Hex(EVPDigest(cInfo,5))+']')
conout('SHA384 ......... ['+Str2Hex(EVPDigest(cInfo,6))+']')
conout('SHA512 ......... ['+Str2Hex(EVPDigest(cInfo,7))+']')

Return

// Converte cada byte da string em uma string com 2 caracteres
// em hexadecimal, representando o valor do byte ( de 00 a ff ) 
STATIC Function Str2Hex(cBuffer)
Local cRet := '', nI
For nI := 1 to len(cBuffer)
  cRet += padr(__dectohex(asc(substr(cBuffer,nI,1))),2,'0')
Next
Return cRet

Com esta função, podemos gerar quaisquer um dos hashes da lista acima. Agora vamos ver o resultado no console do Totvs Application Server:

String ......... [Hello AdvPL]
MD5 ............ [cab49bf9a88ee1c3bfa6c34220edb58e]
RIPEMD160 ...... [ae2497e1672cce7642e329da57ba7fd6b4d5334e]
SHA1 ........... [d7e0a366d6f262c9bca0f3fe89c060f9b876f6ed]
SHA224 ......... [929692e8d0e887e887c82fb26af9b799a311c44c793845ddaceb7073]
SHA256 ......... [a06b154db33e70fab8bed58a9854975b97ea10b8e8f3a097b36f2956fd6f4019]
SHA384 ......... [918a60a0a2c080771b6ef194af54ee22af1c6046544dc5f3f21d5d4d3e202ba1d9249766339f4a5dc743cc2ba5969ed1]
SHA512 ......... [8be7f9a5286c3ed334511572ecbc41fcfb3fe4a1bb6070b2b16b30737e9df022e7781c9793873da7647996bd19485b58b84f5d4aa0106f3c7c84566ae1241022]

Agora, vamos rever a lista de funções para ver o que faltou:

As funções SHA256(), SHA384() e SHA512() recebem os mesmos parâmetros da SHA1(), e retornam o hash calculado usando o respectivo algoritmo, sem mais mistérios. MD5 e MD5File() já vimos no post anterior, faltou apenas a HMAC().

Função AdvPL HMAC()

HMAC é o acrônimo de Hash-based Message Authentication Code — trata-se de uma construção específica para calcular o código de autenticação de mensagem (MAC) envolvendo uma função hash criptográfica em combinação com uma chave secreta, definida pela RFC 2104.

No primeiro post sobre criptografia (Criptografia em AdvPL – Parte 01) eu havia comentado sobre uma técnica chamada “salting” — salgar — usada para você adicionar um valor fixo adicional — e secreto — na informação para gerar e validar o hash, certo? Por razões óbvias, você “salga” uma informação que você vai armazenar e validar, do seu jeito. A HMAC permite fazer isso mais “elegantemente” 😀

Internamente a função gera um hash criptográfico da string informada como primeiro argumento, usando um método de hash informado no segundo argumento, junto com uma string AdvPL contendo uma palavra-chave no terceiro argumento, retornando uma string contendo o código hash correspondente representado em hexadecimal. Podemos alterar o formato do retorno para uma string em bytes com o hash gerado através do quarto parâmetro. Vamos pro exemplo que fica mais fácil:

User Function Hash3()
Local cInfo := 'Hello AdvPL'
Local cChave := 'abracadabra'

conout("String ...... ["+cInfo+"]")
conout("Chave ....... ["+cChave+"]")
conout("HMAC MD5 .... ["+HMAC( cInfo, cChave, 1 ) +"]")
conout("HMAC SHA1 ... ["+HMAC( cInfo, cChave, 3 ) +"]")
conout("HMAC SHA256 . ["+HMAC( cInfo, cChave, 5 ) +"]")
conout("HMAC SHA512 . ["+HMAC( cInfo, cChave, 7 ) +"]")

Return


// Resultado no console

String ...... [Hello AdvPL]
Chave ....... [abracadabra]
HMAC MD5 .... [8fe3373f9a96fd5cf8f3ec1c038b26b9]
HMAC SHA1 ... [d4993adf35c2377417e281d77c5134cc6c2cecde]
HMAC SHA256 . [06245e76c80b6e1a6e955eb94fe1577540f6ea8644d0e55c69d590eddaeb44a1]
HMAC SHA512 . [e8a8edcec569d5ea8d31d6a9880eb145232d2ccf29ad624f8f0f575dd71372c530eee0436c9a3aa639a416c989dbe3b06d03f5cee369a4729f5675e8d8f9972f]

Os métodos suportados de hashing usados pela função são MD5, SHA1, SHA256 e SHA512, sendo o seu retorno correspondente ao método internamente utilizado. Da mesma forma que as demais funções de hashing, ela não é reversível, então a verificação de um hashing gerado pela HMAC() somente pode ser feita recalculando o hash do conteúdo original, e tendo a palavra-passe utilizada.

Função HASH não criptográfica

Até agora vimos funções de hash criptográfico, que têm as seguintes premissas — leia-se `hash` onde está escrito `resumo`:

  • deve ser fácil computar o valor de dispersão (hash) para qualquer mensagem
  • deve ser difícil gerar uma mensagem a partir de seu resumo (hash)
  • deve ser difícil modificar a mensagem sem modificar o seu resumo (hash)
  • deve ser difícil encontrar duas mensagens diferentes com o mesmo resumo (hash).

Porém, o conceito de hash é simplesmente gerar um valor de tamanho fixo baseado em um conteúdo de tamanho variável. Um hash não criptográfico é usado por exemplo para acelerar buscas em listas de tamanhos variáveis, que torna a busca por valores muito, muito rápida. Este artifício chama-se HASHMAP.

HASHMAP

Vamos partir por exemplo de uma lista de palavras ordenada com 1000 (mil) palavras. Com a lista está ordenada, a operação de busca pode fazer uma pesquisa binária — compara direto o texto a ser buscado com o elemento no meio da lista, se for menor, ignora tudo pra baixo e refaz a busca, se for maior ignora tudo pra cima e refaz a busca, até acabar a lista ou encontrar o elemento pesquisado, o que vier primeiro.

Na pior das hipóteses, em uma pesquisa binária em uma lista com 1000 elementos, a primeira busca descarta 500, a segunda 250, a terceira 125, a quarta 62, a quinta 31, depois 16, 8, 4, 2, 1 — e com apenas 10 comparações foi possível determinar que um determinado valor não existe na lista, certo ?

Agora, se ao invés disso, criarmos na memoria uma lista sequencial (Array), onde pré-alocamos um determinado número de elementos, por exemplo 2048 elementos, acessados diretamente pelo índice do array (de 1 a 2048), onde cada elemento é um outro array vazio, e criamos uma função de hash não criptográfico, que a partir de strings de tamanho variável, gere um número entre 1 e 2048, ao inserir um dado calculamos o hash da informação e inserimos ela diretamente no node correspondente. Com isso, você criou um HASHMAP (ou Mapa de Hash) de tamanho 2048.

Na hora de fazer a busca, a primeira etapa é calcular o hash para já buscar o array com os elementos de mesmo hash direto, em tempo constante. Depois, você compara o que você quer buscar apenas com os poucos elementos que eventualmente podem apresentar colisão de hash. Você reduz de 10 comparações para um cálculo de hash e uma comparação, fazendo apenas uma comparação adicional para cada colisão 😀

HASHMAP nativo no AdvPL

Em AdvPL existem um conjunto de funções para criar um hashmap para Arrays e até uma classe para isso — veja no link da TDN TDN – Manipulação de matriz (HashMap) — com elas nem precisamos criar o nosso hash, ela cria um mapa internamente, e permite buscas em tempo linear — não tende a crescer mesmo que a lista seja bem grande. Este recurso já foi visto em posts anteriores no blog, veja as referências no final do post.

Nem preciso dizer que, dependendo das diferenças entre os conteúdos dos elementos do array, não é fácil fazer uma função de hash para gerar um mapa de tamanho fixo que evite colisões, mesmo com mais elementos no mapa do que elementos no array. Logo, reinventar a roda é desnecessário para estes casos, use as funções de HASHMAP para Arrays do AdvPL e seja feliz !!! ❤

Conclusão

Agora que já vimos praticamente tudo sobe hash, vamos entrar no mundo dos certificados digitais e chaves criptográficas 😀

Espero que tenham gostado, e desejo a todos TERABYTES DE SUCESSO !!!

Referências

 

 

Criptografia em AdvPL – Parte 01

Introdução

O AdvPL possui várias funções nativas da linguagem para hashing, criptografia e assinatura digital. Nesta sequência de post, vamos entrar um pouco mais fundo para entender o que é cada uma dessas coisas, o que fazem e como utilizá-las.

HASH

Explicando de forma simples, uma função de HASH gera uma informação de tamanho fixo a partir de dados de tamanho variável. Trata-se de uma forma de gerar um identificador diferente de tamanho fixo para informações quaisquer. Uma função de HASH criptográfico também é chama de função de dispersão criptográfica. Um HASH é uma função de criptografia unidirecional, isto é, não reversível — um HASH gerado a partir de uma informação não permite recuperar a informação original.

CRIPTOGRAFIA

Em linhas gerais, trata-se do uso de uma (entre várias) metodologias de codificação e decodificação de um bloco de dados, reversível, onde o método empregado pode tornar de difícil a impossível recuperar o seu conteúdo original, e apenas quem codificou ou quem sabe decodificar a mensagem consegue fazê-lo. Este recurso é usado para armazenamento e tráfego de dados sensíveis, onde mesmo que alguém intercepte ou veja os dados, o uso de um método criptográfico “forte” — veremos depois o que isso significa — torna impossível saber o que aquilo significa realmente. Usada por exemplo em conexões seguras ( HTTPS, SSL/TLS ) e assinaturas digitais.

ASSINATURA DIGITAL

Assinatura digital (não confundir com assinatura eletrônica) é, em poucas palavras, o uso de HASH junto com criptografia para determinar de forma confiável que uma mensagem recebida foi gerada pelo emissor (confirma o emissor da mensagem), íntegra (a mensagem originalmente gerada pelo emissor não foi alterada) e irretratável (o emissor não pode negar que a informação foi por ele gerada), com tal nível de segurança que, a assinatura digital (ou firma digital) substitui legalmente —  para fins jurídicos — a assinatura física de um documento.

O que temos em AdvPL ?!

No TDN — Totvs Developer Network — dentro da árvore das funções AdvPL, existe um ramo dedicado às funções de Segurança (http://tdn.totvs.com/pages/viewpage.action?pageId=6063905), e dentro dele duas seções de funções:

As funções sob a árvore de Criptografia referem-se a Criptografia e Hash, enquanto a árvore Genérica possui funções auxiliares para informações e conversões entre frmatos de certificados digitais. Vamos separar elas por grupo de funcionalidade nas listas abaixo:

Funções de HASH

Funções de Criptografia

Assinatura Digital 

Assinatura digital com HSM

Chaves Criptográficas e Certificados Digitais

Inicialmente, vamos começar vendo em mais detalhes o que é e onde podemos usar um HASH !

HASH, o que é e como funciona ?

Beleza, por que eu preciso de uma função de HASH, por que existe mais de uma, onde eu preciso usar isso ? Bem, vamos por partes. Como vimos na descrição resumida, uma função de HASH em si não é exatamente uma função criptográfica, que podem ser usadas para fins específicos, e usadas junto com funções criptográficas.

Eu acredito ser mais prático e didático partir para um exemplo de uso, e a partir dele abordar os detalhes: Imagine que você vai montar uma determinada aplicação WEB — um site ou portal — onde determinados conteúdos requerem uma autenticação de usuário para acesso — normalmente feitos com e-mail e uma senha.

Para estar em conformidade com as diretrizes de segurança, tanto suas como as dos usuários cadastrados nesta aplicação, a senha usada pelo usuário é uma informação “sensível”, ninguém além do usuário deve ter acesso a senha que ele usou — NEM VOCÊ que criou o site. Porém, você precisa usar um método de autenticação, que confirme se o usuário está cadastrado e têm acesso ao site, e se a senha digitada é daquele usuário.

Ao criar a sua tabela de usuários do site, se você gravar a senha, mesmo que criptografada de alguma forma, você é capaz de recuperá-la. Se esta informação cair na mão de terceiros e a criptografia utilizada for descoberta — você usou um método “fraco” ou a sua chave de criptografia “vazou”, isso pode causar prejuízos incalculáveis, pois muitos usuários não atentos às melhores práticas de definição de senhas, fatalmente usam a mesma senha de autenticação para outros web sites…

A alternativa mais elegante e segura para todos é usar uma função de HASH. Com ela, quando o usuário se cadastrar no seu site, e você receber a senha que ele quer utilizar, você não grava a senha na base de dados, mas sim um HASH da senha. Lembrando que uma função de HASH — bem projetada — não é reversível, porém é determinística — a mesma entrada gera a mesma saída.

Logo, quando o usuário for se autenticar, quando ele informar o e-mail e a senha, você busca as informações do usuário no seu cadastro usando o e-mail, gera o HASH da senha que ele informou, e compara com o HASH da senha que ele forneceu quando se cadastrou. Se eles forem iguais, o usuário digitou a senha correta de acesso.

Existem muitos sites na internet que (ainda) não seguem as melhores práticas de segurança da informação. Podemos constatar isso em alguns deles quando usamos o recurso “Esqueci minha senha”: Se o site envia um e-mail pra você com a sua senha, ele guardou a sua senha, e não um HASH dela 😛

Diferenças de HASH

Cada função de HASH normalmente leva o nome do algoritmo utilizado para o cálculo do HASH, por exemplo:

  • MD5 = MD5 Digest Algorithm
  • SHA1 = Secure Hash Algorithm 1

Uma função de HASH recebe dados de um tamanho variável, e gera um novo dado de tamanho fixo e de forma determinística a partir do dado fornecido. O que muda entre cada função de HASH é a forma que ela gera o HASH e o tamanho da informação resultante. Por exemplo:

Um HASH usando MD5 usa um algoritmo que gera, para cada informação recebida, um código de 128 bits — ou 16 bytes — normalmente representada por 32 caracteres em hexadecimal (base numérica 16, que usa os números de 0 a 9 e os caracteres de ‘a’ a ‘f’).

Já um HASH usando SHA1 gera um código de 160 bits (20 bytes), normalmente representados por 40 caracteres em hexadecimal. Se você procurar as origens de ambos, vai descobrir que ambos são evoluções do algoritmo MD4 — porém o SHA1 foi projetado pela Agência de Segurança Nacional Americana (NSA).

Todos os demais SHA* ( SHA-256, SHA-384, SHA-512) são algoritmos baseados no SHA1, que geram chaves de tamanhos maiores — o próprio nome da chave indica quantos BITS são utilizados, para er o tamanho em bytes da chave divida o número de bits por 8, e para o tamanho da chave em hexadecimal, multiplique o tamanho em bytes por 2.

  • SHA-256 | 256 Bits | 32 Bytes | 64 caracteres em hexadecimal
  • SHA-384 | 384 Bits | 48 Bytes | 96 caracteres em hexadecimal
  • SHA-512 | 512 Bits | 64 Bytes | 128 caracteres em hexadecimal

Exemplo em AdvPL

Vamos partir de um programa que, a partir de uma determinada informação, gere os hashes MD5, SHA1, SHA256 e SHA512 para o texto “Hello AdvPL”

User Function HashTest()
Local cInfo := 'Hello AdvPL'

conout('String Fornecida .... ['+cInfo+']')

cMD5 := MD5(cInfo)
conout('MD5 ............ ['+cMD5+']')
cSha1 := SHA1(cInfo)
conout('SHA1 ........... ['+cSha1+']')
cSha256 := SHA256(cInfo)
conout('SHA256 ......... ['+cSha256+']')
cSha512 := SHA512(cInfo)
conout('SHA512 ......... ['+cSha512+']')

Return

/* 
Resultado para "Hello AdvPL"

String Fornecida .... [Hello AdvPL]
MD5 ............ [cab49bf9a88ee1c3bfa6c34220edb58e]
SHA1 ........... [d7e0a366d6f262c9bca0f3fe890c06f9b876f6ed]
SHA256 ......... [0a6b154db33e07fab8bed58a9854975b97ea10b8e8f3a097b36f2956fd6f0419]
SHA512 ......... [8be7f9a5286c3ed334511572ecbc41fcfb3fe4a1bb0670b2b16b30737e9d0f22e7781c9793873da7647996bd19485b58b84f5d4a0a016f3c7c84566ae1240122]
*/

Agora, vamos ver o que acontece se eu alterar o texto de  “Hello AdvPL” para “Hello AdvPl” — eu troquei apenas a última letra “L” de maiúsculo para minusculo.

String Fornecida .... [Hello AdvPl]
MD5 ............ [203ac52a0d8e698846b9c9e0c199871e]
SHA1 ........... [96481d2963dda4b9b3ffc76fa10f1873fdb6cbbf]
SHA256 ......... [604bae14779f7f07bea48836d19e225df61c550b0680e477c8ffd0c60465caa6]
SHA512 ......... [0a1aaa24f5c98ebcd1c0f7ffa13cc4fbd854e5696bf040e47a7d2fc571345436aedbcdc26c6ace5cc8926d1e566250c9144fcb86d163cffee89e54b427baa79a]

Só de bater o olho entre os hashes gerados, dá pra ver que a alteração de uma letrinha na mensagem gerou um hash totalmente diferente. Vou colocar os dois hashes MD5 um embaixo do outro:

HASH MD5 ............ [cab49bf9a88ee1c3bfa6c34220edb58e]
HASH MD5 ............ [203ac52a0d8e698846b9c9e0c199871e]

Se você pegar o texto utilizado, e usar qualquer ferramenta on-line para cálculo de hash no padrão escolhido, os resulados serão os mesmos. Por exemplo, ao informar o texto “Hello AdvPl” usando o https://emn178.github.io/online-tools/sha512.html , o hash gerado será o mesmo calculado pelo AdvPL.

Vulnerabilidades gerais do HASH

Uma vulnerabilidade básica do hash é justamente ele ser determinístico — um mesmo valor informado sempre gera o mesmo HASH. Logo, isso possibilita ataques de reversão baseados em dicionários — vou explicar isso….

Senhas curtas, fracas, baseadas em palavras normalmente usadas, podem ser usadas para compor um dicionário de senhas. Nomes de cidades, times de futebol, signos, números como “123456” ou “000000”, etc… Basta o cidadão que conseguir colocar as mãos no arquivo de dados com os emails e os hashes, e fazer um programa para gerar os hashes das palavras do dicionário que ele montou para ver se o hash “bate” — assim ele consegue recuperar a informação original “no chute”, e saber a senha que você usa.

Contorno operacional

Normalmente essa vulnerabilidade é contornada de forma bem simples, mas precisa ser “secreta”: No caso do exemplo onde eu sugeri o uso de salvar a senha do usuário usando um HASH, nada impede que você acrescente junto da senha uma informação adicional fixa e “secreta”, usando a mesma junto da senha para gerar o hash de cadastro, e para validar o login. Com isso, o hash gerado não vai apenas ser baseada na senha do usuário, mas sim na senha junto ou mesclara com uma informação adicional qualquer. Este artifício é conhecido como “salgar” a informação (ou Salting).

Conclusão

Por hora já temos bastante informação para avaliar, para mais detalhes das implementações consulte os links de referência no final do post. E até agora o que vimos foi meramente uma “introdução” assunto 😛  No próximo post, vamos ver um pouco mais sobre cada tipo de HASH e algumas vulnerabilidades especificas e intrínsecas de alguns deles.

Agradeço novamente a audiência e desejo a todos TERABYTES DE SUCESSO !!!

Referências

 

CRUD em AdvPL – Parte 14

Introdução

No post anterior, criamos um programa para servir de “Menu” para a Agenda e outras funcionalidades a serem criadas pela aplicação. Porém, não foi colocada nenhuma proteção para a execução do programa — Controle de Acesso ou similar. Vamos ver como fazer isso de forma segura e elegante, e ver alguns parágrafos sobre Segurança da Informação.

Controle de Acesso

Quando pensamos em restringir o acesso a uma determinada informação, precisamos avaliar o quão importante é a informação em si, e o quão desastroso seria se outra pessoa — além de você — tivesse acesso a esta informação. Determinado este fator, e ele sendo considerado de alta importância, precisamos ver quais são as formas ou caminhos de acesso a informação que podem ser utilizadas, e não apenas como protegê-las, mas o custo disso.

Quando me refiro a custo, não necessariamente estou falando de dinheiro, mas em custo de implementação — em horas — e custo de acesso a informação — desempenho da aplicação ser diminuída em virtude das barreiras de segurança. Um outro fator também importante é “Quanto vai me custar se eu perder a informação ?!” — já este aspecto também é tratado na Segurança da Informação, pois mesmo que a informação não tenha valor para outra pessoa, para você ela deve ter.

E você está sujeito a perder seus dados de várias formas — desde um ataque intencional para prejudicar você ou a sua Empresa, até mesmo um incidente com um ou mais equipamentos … por exemplo, a sala dos servidores ficava no subsolo da empresa, e devido a uma enchente, a água alagou a sala até o teto … danificando permanentemente os computadores  e os discos de dados. Então você lembra que têm um BACKUP (cópia) dos dados, feito no dia anterior — que infelizmente estava em outro servidor, NA MESMA SALA 😐 Mas esse aspecto de segurança contra desastres a gente aborda em outro tópico … risos …

Usuário e Senha

Pensando inicialmente como um usuário da Agenda, e eu quero que somente pessoas que eu autorize tenham acesso para ler e mexer na minha Agenda, exigir na entrada do programa o fornecimento de um nome ou identificador do operador/usuário e uma senha já é um bom começo.

Se, por outro lado, eu quero definir que, um determinado usuário não pode ver ou alterar determinados contatos, ou não pode excluir ninguém da agenda, mas outro usuário pode, podem ser criados mais controles — como direitos de acesso e operação — que podem ser definidos por usuário ou ainda por grupos de usuários, e por operação. Quando trabalhamos com muitos usuários e direitos, torna-se vantajoso criar grupos de usuários e dar os direitos comuns ao grupo, e depois adicionar ou relacionar o usuário a um ou mais grupos. Por definição, um usuário que pertence a um grupo herda os direitos do grupo. Esta abordagem é muito comum em sistemas operacionais (Windows, Linux, Unix, etc.)

Restrições e/ou Liberações

Normalmente partimos de duas abordagens básicas: Restringir ou Liberar. Podemos partir de um sistema de segurança aberto — onde tudo é permitido — e inserir restrições — usuário pode tudo, exceto operações X e Y — ou partir de um sistema de segurança fechado — onde nada é permitido — e as operações ou recursos devem ser explicitamente liberados para um operador ter acesso as operações.

Ainda podemos trabalhar de forma mista, onde por exemplo as operações de um determinado recurso — cadastro de usuários, por exemplo — por padrão é bloqueado para todos, exigindo liberação para acesso, e o acesso aos dados da agenda — liberado por padrão — mas que, mediante a inserção de restrições, podem ter algumas operações ou mesmo o próprio acesso a rotina bloqueados.

Via de regra, um controle de acesso visa tratar a exceção. Logo, se a maioria dos operadores deve ter acesso a agenda, é mais fácil e custa menos inserir restrições quando e onde necessário. Por outro lado, se ter acesso a um determinado recurso é a exceção — via de regra a maioria não deveria ter acesso — então optamos por trabalhar com uma liberação.

Acesso externo (por fora da aplicação)

Eu posso não ter acesso ao programa de Agenda, porém o programa usa um Banco de Dados para armazenar as informações. Se o operador da máquina estiver usando o meu terminal, e o meu Banco de Dados tiver uma relação de confiança com o meu usuário local, eu abro a ferramenta de administração do Banco de Dados, e posso fazer o que eu quiser com os dados, desde consultar até excluir. Uma alternativa é criar o banco com um usuário diferente, com senha forte, e com autenticação explícita por usuário e senha.

Se eu tenho acesso ao computador onde a Agenda está instalada, mesmo que eu não tenha acesso ao Banco de Dados por dentro de uma ferramenta, eu posso tentar parar o serviço do Banco, copiar os arquivos de dados e logs do SGBD, e montar o banco em outro computador. A alternativa para proteger um acesso aos dados mediante cópia é habilitar uma criptografia dos dados no próprio Banco de Dados. Assim, mesmo que alguém consiga copiar o Banco inteiro, sem a chave de segurança ninguém vai entender o que está gravado ali. Alternativas como essa exigem planejamento e controle, pois se você mesmo perder a chave, nem você mais acessa os dados.

Se o seu equipamento está conectado na Internet, e você não tomou medidas de segurança, desde o procedimento de não instalar qualquer coisa de qualquer lugar no equipamento, e não bloqueou alguns acessos e serviços normalmente visados e com brechas conhecidas de ataque, ou colocou uma senha fraca em um usuário com direitos administrativos no seu equipamento, um acesso remoto na máquina tem praticamente o mesmo efeito como se o intruso estivesse realmente na frente do equipamento — quando ele pode estar a 2 quadras ou 50 mil quilômetros de distância.

RANSOMWARE

Um adendo especial, sobre um novo tipo de ataque, que já fez algumas vítimas pelo mundo, é o RANSOMWARE — uma aplicação nociva, que não visa roubar dados do equipamento, mas “sequestrá-los”. O aplicativo age como um Vírus ou Trojan, mas uma vez infectado o equipamento, ele se mete no acesso aos dados do disco, e criptografa arquivos, pastas, o que ele acha que deve ou os dados para o qual ele foi programado para criptografar. Em um determinado momento, ele pode simplesmente restringir o acesso às pastas e arquivos, ou mesmo apagar os arquivos originais, e exigir um pagamento para o fornecimento da chave capaz de voltar os dados que ele criptografou na sua forma original, ou exige uma senha para o próprio programa malicioso desfazer e restaurar os dados dos arquivos originais — normalmente com o pagamento de alguma importância em dinheiro não rastreável, como cripto-moedas.

Estudo de caso – Agenda

Por hora a ideia de controle de acesso na Agenda, além de fins didáticos, é começar de forma simples, por exemplo, para tratar um cenário onde eu quero que apenas minha esposa e eu possamos abrir a Agenda, mas sem bloquear nenhuma operação ou contato da agenda. Nós dois podemos ver todas as informações de todos os contatos da Agenda, não importa quem cadastrou o contato, e podemos fazer todas as operações com os contatos — como alterar dados, alterar foto, excluir o contato, enfim.

Neste caso, precisamos inicialmente de uma nova tabela, com pelo menos dois campos, um para o nome ou identificação do usuário ou operador — pode ser um nome, ou um e-mail, e outro campo para a autenticação de acesso, como por exemplo uma senha. Antes de implementar isso, vamos avaliar nossa necessidade e as possibilidades de se implementar esta solução.

Usuário ou e-Mail ?

Por ser um sistema local, um nome único de usuário já resolveria a questão de identificação. Porém, pensando um pouco além do óbvio, eu bem que poderia usar um e-mail. Afinal, lembra do que acontece quando você “perde a chave”? Nem você entra mais na sua casa.

Vantagens do e-Mail

  • Se o próprio operador esquece da senha, e a aplicação é capaz de enviar um e-mail ao usuário, ele pode usar um recurso como por exemplo “Password Reset”, onde a aplicação gera uma chave temporária de acesso para aquele usuário, e envia a chave no e-mail dele. Somente ele deve ter acesso ao e-mail, logo, uma vez que ele acesse o sistema com a chave que o sistema gerou, a aplicação tenta garantir que é de fato aquele usuário que está realizando o acesso, e permite a ele redefinir sua senha de acesso.
  • Dificilmente um usuário se esquece do próprio endereço de e-mail.
  • Sem o e-mail, o usuário precisaria entrar em contato com o Administrador do Sistema, de alguma forma provar sua identidade, e pedir para ele uma troca de senha. Quando falamos de um sistema local de Agenda, pra usar em casa, sem problemas.  Mas, pensando em algo um pouco maior, algo como a Agenda disponível na Internet, é um desperdício criar um suporte para atender usuário que perdeu senha, se você pode dar a ele um procedimento seguro de provar sua identidade e restaurar sozinho e com segurança seu acesso ao sistema.

Autenticando por Senha

Antes de mais nada, a respeito de qualquer tipo de senha em um sistema informatizado: Nunca grave a senha em um sistema de controle de acesso. Sim, é isso mesmo: NÃO GRAVE A SENHA.

Certo, então como vêm a pergunta: Se eu não gravar a senha, como eu vou conseguir validar a senha que o operador digitou na entrada do sistema está certa ?! Bem, primeiro vamos aos riscos: Uma tabela de usuários e senhas vale muito para pessoas mal-intencionadas. Muitos usuários na internet usam senhas fortes para diversos recursos, mas acabam usando a mesma senha para outros recursos. Logo, mesmo que você grave a senha que o operador digitou usando algum tipo de criptografia, se alguém descobre o algoritmo de descriptografia, ele terá acesso a todas as senhas de todos os usuários.

Uma alternativa bastante segura é gerar um hash (ou dispersão criptográfica) unidirecional. Na prática, você usa um algoritmo que é capaz de gerar uma sequência de dados a partir de uma informação fornecida, mas o algoritmo não é capaz de restaurar o dado original a partir da sequência de dados (hash) gerado. Um bom exemplo disso é o MD5 — vide referências no final do post. A partir de uma informação fornecida, o algoritmo MD5 gera uma sequência hexadecimal de 128 BITS, mas a partir desta sequência ele não é capaz de desfazer a operação e informar qual foi a informação que gerou aquele hash.

Logo, quando o usuário informar a senha de acesso que ele gostaria de usar, a aplicação gera um MD5 desta senha, e grava o resultado no banco de dados, atrelado a este usuário. No momento que este usuário for entrar no sistema, e fornecer o e-Mail e Senha, você localiza ele no cadastro pelo e-Mail, e gera novamente o MD5 da senha que ele informou. Se ele informou a mesma senha, o resultado do MD5 será o mesmo. Assim, nem você sabe a senha original, nem quem conseguir roubar ou copiar esta tabela vai saber.

Existe a possibilidade de colisão, isto é, duas senhas diferentes gerarem o mesmo hash. Porém, como estamos falando de um hash de 128 bits, sabe quantas são as possíveis combinações? 2^128 (dois elevado a potência 128), algo em torno de 3.40e+38 combinações diferentes — imagine que 64 bits = 18.446.744.073.709.551.615 ( dezoito quintilhões, quatrocentos e quarenta e seis quatrilhões, setecentos e quarenta e quatro trilhões, setenta e três bilhões, setecentos e nove milhões, quinhentos e cinqüenta e um mil, seiscentas e quinze possibilidades), agora multiplica esse número por dois, sessenta e quatro vezes seguidas 😛 

Vamos ao AdvPL

Primeiro, vamos criar a função responsável pela criação e abertura da tabela de usuários. Ela é praticamente uma cópia com alterações da função de criação da tabela de Agenda.

// --------------------------------------------------------------
// Abertura da Tabela de USUARIOS da Agenda
// Cria uma tabela chamda "USUARIOS" no Banco de dados atual
// configurado no Environment em uso pelo DBAccess
// Cria a tabela caso nao exista, cria os índices caso nao existam
// Abre e mantém a tabela aberta em modo compartilhado
// --------------------------------------------------------------
STATIC Function OpenUsers()
Local cFile := "USUARIOS"
Local aStru := {}
Local aDbStru := {}
Local nRet

While !GlbNmLock("USUARIOS_DB")
  If !MsgYesNo("Existe outro processo abrindo a tabela USUARIOS. Deseja tentar novamente ?")
    MSgStop("Abertura da tabela USUARIOS em uso -- tente novamente mais tarde.")
    QUIT
  Endif
Enddo

// Cria o array com os campos do arquivo 
aadd(aStru,{"IDUSR" ,"C",06,0})
aadd(aStru,{"LOGIN" ,"C",50,0})
aadd(aStru,{"SENHA" ,"C",32,0})

If !TCCanOpen(cFile)
  // Se o arquivo nao existe no banco, cria
  DBCreate(cFile,aStru,"TOPCONN")
  Else
  // O Arquivo já existe, vamos comparar as estruturas
  USE (cFile) ALIAS (cFile) SHARED NEW VIA "TOPCONN"
  IF NetErr()
    MsgSTop("Falha ao abrir a tabela USUARIOS em modo compartilhado. Tente novamente mais tarde.")
    QUIT
  Endif
  aDbStru := DBStruct()
  USE

  If len(aDbStru) != len(aStru)
    // Estao faltando campos no banco ? 
    // Vamos alterar a estrutura da tabela
    // Informamos a estrutura atual, e a estrutura esperada
    If !TCAlter(cFile,aDbStru,aStru)
      MsgSTop(tcsqlerror(),"Falha ao alterar a estrutura da tabela USUARIOS")
      QUIT
    Endif
    MsgInfo("Estrutura do arquivo USUARIOS atualizada.")
  Endif

Endif

If !TCCanOpen(cFile,cFile+'_UNQ')
  // Se o Indice único da tabela nao existe, cria 
  USE (cFile) ALIAS (cFile) EXCLUSIVE NEW VIA "TOPCONN"
  IF NetErr()
    MsgSTop("Falha ao abrir a tabela USUARIOS em modo EXCLUSIVO. Tente novamente mais tarde.")
    QUIT
  Endif
  nRet := TCUnique(cFile,"LOGIN")
  If nRet < 0 
    MsgSTop(tcsqlerror(),"Falha ao criar índice único")
    QUIT
  Endif
  USE
EndIf

If !TCCanOpen(cFile,cFile+'1')
  // Se o Indice por ID nao existe, cria
  USE (cFile) ALIAS (cFile) EXCLUSIVE NEW VIA "TOPCONN"
  IF NetErr()
    MsgSTop("Falha ao abrir a tabela USUARIOS em modo EXCLUSIVO. Tente novamente mais tarde.")
    QUIT
  Endif
  INDEX ON IDUSR TO (cFile+'1')
  USE
EndIf

If !TCCanOpen(cFile,cFile+'2')
  // Se o indice por LOGIN nao existe, cria
  USE (cFile) ALIAS (cFile) EXCLUSIVE NEW VIA "TOPCONN"
  IF NetErr()
    MsgSTop("Falha ao abrir a tabela USUARIOS em modo EXCLUSIVO. Tente novamente mais tarde.")
    QUIT
  Endif
  INDEX ON LOGIN TO (cFile+'2')
  USE
EndIf

// Abra o arquivo de agenda em modo compartilhado
USE (cFile) ALIAS (cFile) SHARED NEW VIA "TOPCONN"

If NetErr()
  MsgSTop("Falha ao abrir a tabela USUARIOS em modo compartilhado. Tente novamente mais tarde.")
  QUIT
Endif

// Abre os indices, seleciona ordem por ID
// E Posiciona no primeiro registro 
DbSetIndex(cFile+'1')
DbSetIndex(cFile+'2')
DbSetOrder(1)
DbGoTop()

// Solta o MUTEX 
GlbNmUnlock("USUARIOS_DB")

Return .T.

Para quem ainda está usando um binário 7.00.131227, que não têm as funções GlbNmLock() e GlbNmUnlock(), pode temporariamente substituí-las por GlbLock() e GlbUnlock() — a diferença é que o Lock realizado é global, isto é, desconsidera o nome informado como parâmetro.

Agora, vamos fazer a função de LOGIN, porém vamos atentar a um detalhe: Se eu não quiser habilitar o controle de usuários na minha agenda, eu simplesmente deixo o cadastro de usuários vazio.

// ---------------------------------------------------
// Função responsável pelo controle de acesso - Login
// Somente exige autenticação se o cadastro de usuários tiver 
// pelo menos um usuário 
// ---------------------------------------------------
STATIC Function ChkUser(oDlg)
Local lOk := .T.
// Abre cadastro de usuarios
OpenUsers()
// Vai para o topo do arquivo 
DbSelectarea("USUARIOS")
DBGoTOP()
If !EOF()
  // Se existem usuarios na tabela de usuarios, 
  // o login foi habilitado . 
  lOk := DoLogin(oDlg)
Endif
// Fecha o cadastro de usuarios 
DbSelectarea("USUARIOS")
USE 
If !lOk
  MsgStop("Usuário não autenticado.","Controle de Acesso")
  QUIT
Endif
Return

// Definições para uso da função AdvPL MD5()
#define RAW_DIGEST 1 
#define HEX_DIGEST 2

// Função responsável pelo diálogo e validação do Login
STATIC Function DoLogin(oDlg)
Local cTitle := 'Controle de Acesso'
Local oDlgLogin
Local oGetLogin
Local cLogin := space(50)
Local cPassW := space(16)
Local oBtnOk
Local lGo,lOk

While .T.
  lGo := .F.
  lOk := .F. 
  cLogin := space(50)
  cPassW := space(16)
  DEFINE DIALOG oDlgLogin TITLE (cTitle) ;
    FROM 0,0 TO 90,450 PIXEL;
    FONT oDlg:oFont ; // Usa a mesma fonte do diálogo anterior
    OF oDlg ;
    COLOR CLR_WHITE, CLR_RED

  @ 05+3,05 SAY oSay1 PROMPT "Login" RIGHT SIZE 20,12 OF oDlgLogin PIXEL
  @ 05,30 GET oGetLogin VAR cLogin PICTURE "@!" SIZE CALCSIZEGET(45) ,12 OF oDlgLogin PIXEL

  @ 25+3,05 SAY oSay1 PROMPT "Senha" RIGHT SIZE 20,12 OF oDlgLogin PIXEL
  @ 25,30 GET oGetPassw VAR cPassW SIZE CALCSIZEGET(16) ,12 OF oDlgLogin PIXEL
  oGetPassw:LPASSWORD := .T.

  @ 25,155 BUTTON oBtnOk PROMPT "Ok" SIZE 60,15 ;
    ACTION (lGo := .T. , oDlgLogin:End()) OF oDlgLogin PIXEL

  ACTIVATE DIALOG oDlgLogin CENTER

  If !lGo
    // SE a janela foi fechada, desiste 
    EXIT
  Endif

  DbSelectarea("USUARIOS")
  DBSetOrder(2) // Indice por LOGIN

  If DBSeek(cLogin)
    // Encontrou o Login informado
    If MD5(alltrim(cPassW),HEX_DIGEST) == USUARIOS->SENHA
      // A senha informada "bate" com a senha original
      // Seta que está OK, sai do Login
      lOk := .T.
      EXIT
    Endif 
  Endif

  // Chegou aqui, o login nao existe ou a senha nao confere 
  MsgStop("Login ou senha inválidos. "+;
    "Confirme os dados e repita a operação.", ;
    "Falha de Autenticação")

Enddo

Return lOk

Feito isso dessa forma, conseguimos implementar um controle de acesso simples e eficiente, e bastante seguro, pois a senha original nunca é armazenada. A tela, após implementado um usuário, deve ficar assim:

CRUD - Controle de Acesso

Conclusão

Por hora, sem a inclusão de um usuário, não há autenticação na Agenda. As partes de código publicadas aqui ainda exigem alguns ajustes em outros pontos, por exemplo inserir o Login na inicialização da Agenda. Para pegar o fonte completo, acesse o GITHUB!

Agradeço novamente a audiência, as curtidas e os comentários, e desejo novamente a todos TERABYTES DE SUCESSO 😀 

Referências