Como gerar certificado para o broker MQTT

Por padrão, o broker Mosquitto não utiliza criptografia no canal de dados, na porta 1883. Para uso interno ou para testes não há problema, além de que não é tão simples interceptar o meio na Internet. Porém, não é também uma das tarefas mais difíceis e, se feito, as credenciais serão expostas, não só as mensagens. Nesse artigo veremos como gerar certificado para o broker MQTT Mosquitto, protegendo assim os dados de tráfego. Também mostrarei o uso do certificado no client – dessa vez, por linha de comando, e em uma futura implementação, em um ESP8266 ou ESP32.

Se ainda não configurou um broker MQTT, pode começar por esse artigo. É rápido e fácil e você não precisará de conexão com Internet para fazer seus testes, o que torna o ambiente de desenvolvimento mais seguro.

Instale o openssl

Como gerar certificado é uma tarefa conhecida e praticada por administradores de sistema, provavelmente não haverá muita novidade por aqui. Além do mais, o processo é muito padronizado.

Você pode gerar as chaves onde quiser, no broker ou em outro computador, depois transportá-la para os respectivos diretórios. Eu uso Linux e recomendo que o processo seja feito diretamente no broker ou em uma máquina virtual Linux, caso esteja usando Windows. Para a virtualização, recomendo o VirtualBox – o melhor, em minha opinião.

Considerando que já esteja no Linux, instale o programa openssl:

sudo su
apt-get update
apt-get install openssl

Crie um diretório para trabalhar. Eu fiz tudo diretamente no broker, dentro do diretório /etc/mosquitto, em meu notebook.

mkdir certificado
cd certificado

Agora começa a brincadeira.

Crie uma chave CA

O processo consiste em uma série de comandos. Tenha paciência, porque apesar de ser uma série de comandos estranhos, o processo é simples.

openssl genrsa -des3 -out ca.key 2048

Esse comando gerará o arquivo ca.key.

Crie um certificado usando a chave CA

Agora vamos criar um certificado, cujo nome do arquivo resultante será ca.crt.

openssl req -new -x509 -days 1826 -key ca.key -out ca.crt

Preencha os campos como na imagem a seguir. O common name deve ser o IP do broker, a URL do broker ou o nome de host, se estiver instalando localmente. Meu hostname é dobitaobyte (estou instalando em meu notebook para escrever esse artigo).

Como gerar certificado com openssl

Crie o server.key

Esse já é um dos arquivos utilizados pelo broker. As cópias serão feitas quando tudo estiver concluído.

openssl genrsa -out server.key 2048

Crie o certificado de requisição CSR

Estamos quase na metade já.

openssl req -new -out server.csr -key server.key

Não preencha os atributos extras, isso causará problemas na autenticação.

Como gerar certificado com openssl

Assinar o certificado do servidor

Agora para assinar o certificado do servidor, utilizaremos a chave CA.

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360

Com isso, temos os arquivos:

Como gerar certificado - arquivos resultantes

Três desses arquivos serão utilizados. O ca.crt deve ser colocado no diretório /etc/mosquitto/ca_certificates, enquanto os arquivos server.keyserver.crt devem ser colocado no diretório /etc/mosquitto/certs.

Como gerar certificado - diretórios de destino no broker

Habilitar certificado no broker Mosquitto

Agora será necessária uma modificação no arquivo de configuração do broker, onde será habilitada a porta de dados seguros. Estou mantendo também a porta padrão. Além disso, devemos especificar os arquivos relacionados ao TLS. Meu arquivo de configuração (/etc/mosquitto/mosquitto.conf) ficou desse jeito:

#nao permitir acesso anonimo
allow_anonymous false       
#...                                                              
autosave_interval 1800                                                                    
#...
connection_messages true                                                                  
#destino das msgs de log. Pode apontar pra quantas quiser, uma por linha
log_dest stderr                                                                           
log_dest topic   
#tipos de erro. Tem mais alguns nessa ultima versao, mas aqui ja me basta                                                                         
log_type error                                                                            
log_type warning                                                                          
log_type notice                                                                           
log_type information                                                                      
log_type debug
#...                                                                            
log_timestamp true
#arquivo de passwd                                                                       
password_file /etc/mosquitto/dobitaobyte.pw
#arquivo de acl                                                  
acl_file /etc/mosquitto/dobitaobyte.acl
#para gravar os dados em disco                                         
persistence true
#destino da base de dados.                                                                        
persistence_location /opt/mosquitto/mosquitto_db
#nome para o arquivo de persistencia de dados                                                              
persistence_file mosquitto.db                
#tempo para descarregar da memoria para o disco                                             
persistent_client_expiration 1m  
#um sinonimo de persistence, nao precisa dessa repeticao                                                         
retained_persistence true                                                                 
#abre 1883 em localhost, apenas IPv4
listener 1883 192.168.1.200
#abre em todas as interfaces na 8883, IPv4 e IPv6 (e pode ter mais)
listener 8883 192.168.1.200
#certificados
#tls_version tlsv1
cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate false

Reinicie o serviço e verifique se houve algum erro. Normalmente é emitida uma mensagem quando há erros. De outro modo, apenas confirme com o status:

sudo su
service mosquitto stop
service mosquitto start
service mosquitto status

Utilize o arquivo ca.crt para o client

Os clients, sejam eles quais forem, deverão fazer uso do conteúdo do arquivo ca.crt. No teste, estou utilizando o mosquitto_pubmosquitto_sub. Desse modo, não preciso ainda escrever um programa apenas para depurar se o broker está funcionando adequadamente.

Me subscrevi ao tópico /raspberry criado na ACL, usando a porta 1883 e em outro terminal, me subscrevi ao mesmo tópico, mas com SSL:

#Em um terminal:
mosquitto_sub -h 192.168.1.200 -u SEU_USUARIO -P SUA_SENHA -t '/raspberry/#'
#Em outro terminal:
mosquitto_sub -h 192.168.1.200 -d --cafile ca.crt -p 8883 -u SEU_USUARIO -P SUA_SENHA -t '/raspberry/#' --insecure

No caso, o uso de ‘insecure’ é para não validar o nome do servidor, já que está sendo feito local. Com um servidor contendo uma URL válida esse parâmetro não deve ser necessário.

Para publicar é bastante semelhante, incluindo apenas tópico e mensagem.

#Na porta 1883:
mosquitto_pub -h 192.168.1.200 -u SEU_USUARIO -P SUA_SENHA -t /raspberry/teste -m "sem TLS"
#No canal criptografado:
mosquitto_pub -d --cafile ca.crt -p 8883 -h 192.168.1.200 -u SEU_USUARIO -P SUA_SENHA -t '/raspberry/' -m 'com TLS' --insecure

Fiz o teste nos 4 terminais, como indicado:

 

Ok, funcionou. Mas quem garante que só não abri uma outra porta que não a 1883, sem criptografia? Vamos à prova.

Utilizando tcpdump, analisei o tráfego nas respectivas portas. Sem criptografia, tive que borrar a parte que mostra as credenciais. Circulei a área com o tópico e valor publicado:

sniffing sem SSLJá com a criptografia implementada, não tem muito o que mostrar, pois não passa de um emaranhado de caracteres. Mas veja:

sniffing com ssl

Se ainda tem alguma dúvida ou não sabe interpretar o tcpdump, recomendo esse artigo. Com isso, vimos como gerar certificado para aumentar a segurança nas transações dos dispositivos utilizando o protocolo MQTT.

O certificado é gerado com tempo de validade, depois precisa ser renovado. Apesar de não ser um trabalho constante, é repetitivo, por isso vou mostrar em outro artigo como automatizar a entrada de comandos com a criação de bots em shell script, só acompanhar!

 

Revisão: Ricardo Amaral de Andrade

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.