Resumo da série: Os artigos desta série irão descrever como funciona os passos do procolo utilizado pelos sites que utilizam HTTPS e como é descriptografado essa informação pelo navegador.
Objetivo: Propor ao leitor o entendimento das regras do protocolo HTTPS, a experiência prática de como ele funciona e porque ele é um protocolo seguro.
Requisitos: Os leitores devem ter conhecimentos básicos dos protocolos TCP/IP, HTTP e de como funcionam as conexões clientes (navegadores) e servidores na Web.
Composição: A série é composta de 4 artigos:
- Negociação de Conexão
- Envio do Código Secreto
- Cálculo de Chaves
- Descriptografia
Entendimento técnico dos artigos respectivamente:
- Handshake Protocol
- Utilização de Chaves Assimétricas
- Funcionamento do Algoritmo PRF (Pseudo Random Function)
- Descriptografia
Contéudo de cada artigo:
- Analogia e entendimento da Etapa
- Explicação técnica e algorítmica
- Implementação
Tecnologias: Wireshark para captura de pacotes e chaves para descriptografia. O foco da implementação é o parseamento dos bytes e regra de negócios, entendendo que esses bytes da camada de aplicação já foram capturados pelo leitor/desenvolvedor por alguma biblioteca ou extensão.
Implementação: O algoritmo será implementado na linguagem PHP para o exemplo proposto.
Descriptografia de Web Sites HTTPS – Parte 01: Negociação de Conexão
Nesta série de quatro artigos iremos compreender, capturar dados e descriptografar informações dentro de uma conexão HTTPS.
Primeiramente, para estabelecermos uma conexão HTTPS utilizamos o protocolo TLS, que cuida da segurança da camada de transporte. Esse protoloco é regulamentado pela RFC 5246.
A conexão HTTPS é realizada entre Cliente e Servidor Web; essa conexão realiza algumas trocas de mensagens até o momento em que a conexão é considerada estabelecida e segura.
O primeiro objetivo é o cálculo de um código secreto (Master Secret) realizado em ambos os lados, ou seja, no cliente e no servidor. O Master Secret é alterado a cada nova conexão. Uma conexão se inicia quando o cliente solicita uma página ao servidor.
Observação: essa conexão pode ser reiniciada quando houver uma suspeita de falha de segurança.
Mensagens da Negociação
1. Inicialmente o cliente envia a mensagem ClientHello ao servidor com um código aleatório (Cliente Random) e uma lista de algoritmos em que o cliente se diz capaz de descriptografar (Cipher Suites).
2. O servidor responde com a mensagem ServerHello contendo outro código aleatório (Server Random) e um algoritmo escolhido da lista que o cliente disse ser capaz de descriptografar (Cipher Suite).
3. O servidor envia o seu certificado na mensagem Certificate, este contém uma Chave Pública (Public Key). O navegador também analisa se o emitente do certificado é uma fonte confiável, porém não iremos verificar essa condição.
4. Na sequência, o servidor envia a mensagem ServerHelloDone, indicando que está esperando os dados do cliente.
Captura
A captura de pacote desta série é demonstrada pelo software Wireshark, a versão utilizada neste artigo é 1.10.6. As classes implementadas recebem em seus métodos os pacotes capturados sempre na última camada, ou seja de aplicação.
Para a captura, foi utilizado o acesso a um site local, configurado pelo servidor Apache.
Observação: Não é necessário ter um certificado com identidade confirmada para descriptografar o HTTPS e executar o exemplo deste artigo.
Importante: Lembrando um pouco do protocolo TCP, o pacote de resposta terá que ter o valor do campo Sequence Number igual ao valor campo Acknowledgment Number correspondente ao pacote enviado. Para facilitar há teclas de atalho no Wireshark, para ir ao pacote correspondente próximo (CTRL + .) e para voltar ao anterior (CTRL + ,).
1. Ao se tratar de um protocolo HTTPS se inicia a negociação de conexão com o envio da mensagem Cliente Hello. A imagem abaixo é um print screen do Wireshark com esta mensagem:
O conteúdo do campo Random, descriminado como Cliente Random, gerou os dados no formato hexadecimal “be6fb836c97510ff31fa44a03f4411564a705837460c135feabc6005eb031438”.
2. A resposta do servidor, como já indicado anteriormente, será a mensagem ServerHello.
O conteúdo do campo Random, descriminado como Server Random, gerou os dados no formato hexadecimal “53cf9faaee53ee74d19f91c04810977224c6466dfe2d5b3d3cb2db24e14a7e33”.
O campo CipherSuite gerou os dados no formato hexadecimal “002f”, que corresponde a Cipher Suite “TLS_RSA_WITH_AES_128_CBC_SHA”, ou seja, indica que será utilizado o algoritimo para troca de chaves RSA, o algoritmo para criptografia de dados AES_128_CBC e o Hash SHA para conferencia da autenticidade da informação, este último é conhecido como MAC Key.
Implementação
Na implementação, utilizaremos a linguagem PHP, igual ou superior a versão 5.3.0. Primeiramente iremos implementar a classe e depois chamaremos os métodos implementados. Segue o código da classe SessionTLS e a atribuição dos valores obtidos para Cipher Suite, Client Random e Server Random.
class SessionTLS { private $session_id; private $client_random; private $server_random; private $pre_master_secret; private $master_secret; private $cipher_suite; private $cipher; private $mac; private $client_write_MAC_key; private $server_write_MAC_key; private $client_write_key; private $server_write_key; private $client_write_IV; private $server_write_IV; public function __construct() { $this->session_id = null; $this->client_random = null; $this->server_random = null; $this->pre_master_secret = null; $this->master_secret = null; $this->cipher_suite = null; $this->cipher = null; $this->mac = null; $this->client_write_MAC_key = null; $this->server_write_MAC_key = null; $this->client_write_key = null; $this->server_write_key = null; $this->client_write_IV = null; $this->server_write_IV = null; } public function setCipherSuite($cipher_suite) { $this->cipher_suite = $cipher_suite; } public function setClientRandom($client_random) { $this->client_random = $client_random; } public function setServerRandom($server_random) { $this->server_random = $server_random; } public function setPreMasterSecret($pre_master_secret) { $this->pre_master_secret = $pre_master_secret; } public function PRF($secret, $label, $seed, $size) { throw new Exception("Não implementado"); } public function P_SHA256($secret, $seed, $size) { throw new Exception("Não implementado"); } public function generateMasterSecret() { throw new Exception("Não implementado"); } public function parserCipherMac() { throw new Exception("Não implementado"); } public function getKeyMaterialBytes() { throw new Exception("Não implementado"); } public function getIVSizeBytes() { throw new Exception("Não implementado"); } public function getMacLengthBytes() { throw new Exception("Não implementado"); } public function generateKeyBlock() { throw new Exception("Não implementado"); } public function decrypt($cipherText) { throw new Exception("Não implementado"); } public function decryptOpenSSL($cipher, $cipherText, $key, $IV) { throw new Exception("Não implementado"); } } $TLS = new SessionTLS(); $TLS->setCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA"); $TLS->setClientRandom(hex2bin("be6fb836c97510ff31fa44a03f4411564a705837460c135feabc6005eb031438")); $TLS->setServerRandom(hex2bin("53cf9faaee53ee74d19f91c04810977224c6466dfe2d5b3d3cb2db24e14a7e33"));
Próximo Artigo
Após esse protocolo de troca de informações, se inicia a parte mais importante e fascinante do HTTPS, que é o envio do código secreto, no próximo artigo você entenderá como é feita essa troca de informação.
Na próxima semana, você verá na parte 02 dessa série porque o protocolo é seguro e porque mesmo quando essas informações são interceptadas elas não podem ser decifradas. Até lá.