Segurança MQTT

Como Armazenar Credenciais MQTT com Segurança em Dispositivos Embarcados

Uma comparação prática das formas de proteger usuários e senhas MQTT em dispositivos ESP32 e Linux, da NVS criptografada e criptografia de flash a secure elements e credenciais do systemd protegidas por TPM.

Ilustração de credenciais MQTT protegidas em dispositivos, armazenadas em flash criptografada e em um secure element em uma placa de circuito
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Proteger credenciais MQTT em dispositivos significa garantir que o usuário e a senha que o seu dispositivo usa para chegar ao broker não possam ser lidos a partir de imagens de firmware, de chips de flash copiados, de portas de depuração ou de arquivos de log. Este guia compara as opções práticas em dispositivos ESP32 e Linux, mostra a configuração de cada uma e lista os erros que mais vazam credenciais em campo.

O modelo de ameaças em termos simples

Antes de escolher um método de armazenamento, deixe claro contra quem você está se defendendo:

Atacante Acesso O que ele tenta
Alguém com o seu arquivo de firmware Um .bin de uma página de download ou de um chamado de suporte Procurar strings na imagem
Alguém com um dispositivo Acesso físico, um adaptador USB-serial Copiar a flash via UART, conectar JTAG
Malware ou bug no dispositivo Código rodando no dispositivo Ler arquivos ou memória
Alguém na rede Captura de pacotes Ler a senha no CONNECT

O atacante na rede é tratado pelo TLS na porta 8883 (ou 8084 para WebSockets), que todo broker ConnectMQ suporta com um certificado Let's Encrypt; autenticação MQTT com usuário e senha explica por que as credenciais nunca devem trafegar pela porta 1883. Este artigo se concentra nos outros três: proteger o segredo em repouso no dispositivo.

Regra zero: credenciais não pertencem ao firmware

Um #define MQTT_PASSWORD "..." no código-fonte vai parar no binário do firmware, no histórico do Git, nos logs de CI e em cada cópia da imagem. Executar strings firmware.bin | grep -i pass em um projeto hobby típico muitas vezes a encontra em segundos. O firmware deve ser idêntico em todos os dispositivos; as credenciais devem ser únicas por dispositivo. Mantenha-os separados e grave as credenciais no armazenamento durante o provisionamento seguro de dispositivos IoT.

Opções no ESP32

NVS simples (base, não segura)

A biblioteca Non-Volatile Storage (ou o wrapper Preferences do Arduino) armazena pares chave-valor em uma partição da flash. Ela separa as credenciais do firmware, o que já é uma melhoria, mas os dados ficam sem criptografia. Qualquer pessoa que consiga ler o chip de flash consegue ler a senha.

Criptografia da NVS mais criptografia de flash

O ESP-IDF consegue criptografar partições NVS. No esquema clássico, as chaves de criptografia da NVS ficam em uma partição dedicada nvs_keys, e essa partição é protegida pela criptografia de flash, cuja chave fica armazenada em eFuses que o software não consegue ler de volta. Chips mais novos, como o ESP32-S3 e o ESP32-C3, também suportam um esquema baseado em HMAC que deriva as chaves da NVS de uma chave em eFuse, sem partição nvs_keys.

Uma tabela de partições com uma partição de chaves criptografada:

# Name,    Type, SubType,  Offset, Size,   Flags
nvs,       data, nvs,      ,       0x6000,
nvs_keys,  data, nvs_keys, ,       0x1000, encrypted
phy_init,  data, phy,      ,       0x1000,
factory,   app,  factory,  ,       1M,

Opções relevantes do sdkconfig:

CONFIG_SECURE_FLASH_ENC_ENABLED=y
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
CONFIG_NVS_ENCRYPTION=y
CONFIG_SECURE_BOOT=y
CONFIG_SECURE_BOOT_V2_ENABLED=y

O modo release é importante: o modo de desenvolvimento deixa formas de regravar imagens em texto claro, o que anula o propósito em unidades já enviadas. O Secure Boot complementa a criptografia ao recusar executar firmware que você não assinou, de modo que um atacante não consiga gravar um código que leia e imprima as credenciais descriptografadas. Ambos queimam eFuses de forma irreversível, então teste primeiro em placas sobressalentes e siga passo a passo a documentação de criptografia de flash da Espressif.

Ler as credenciais em um sketch Arduino no ESP32 tem a mesma cara com ou sem NVS criptografada, e é exatamente essa a ideia: a proteção fica abaixo da API.

#include <Preferences.h>

struct MqttCreds { String user, pass, clientId; };

bool loadCreds(MqttCreds &c) {
  Preferences prefs;
  if (!prefs.begin("mqtt", true)) return false;   // somente leitura
  c.user = prefs.getString("user", "");
  c.pass = prefs.getString("pass", "");
  c.clientId = prefs.getString("cid", "");
  prefs.end();
  return c.user.length() && c.pass.length() && c.clientId.length();
}

void logCreds(const MqttCreds &c) {
  // Registra a identidade, nunca a senha
  Serial.printf("MQTT user=%s clientId=%s pass=<%u bytes>\n",
                c.user.c_str(), c.clientId.c_str(), c.pass.length());
}

Secure elements

Um secure element, como o ATECC608 da Microchip, é um chip separado que armazena chaves e executa operações criptográficas sem nunca liberar as chaves privadas. Ele é mais forte para identidade baseada em certificados, em que a chave privada do TLS mútuo nunca sai do chip. Com autenticação por senha, um secure element ainda pode ajudar guardando a chave usada para criptografar o blob da senha na flash, dificultando a extração física. Ele aumenta o custo da lista de materiais, o espaço na placa e o trabalho de integração de drivers, por isso é mais comum em produtos com dados de alto valor ou pressão regulatória.

Opções em dispositivos Linux

Gateways e computadores de borda com Linux têm ferramentas mais ricas.

Permissões de arquivo (base)

Guarde as credenciais em um arquivo legível apenas pela conta de serviço, fora do diretório da aplicação:

sudo install -d -m 0700 -o mqttsvc -g mqttsvc /etc/mqtt-agent
sudo install -m 0600 -o mqttsvc -g mqttsvc credentials.env /etc/mqtt-agent/credentials.env

Isso protege contra outros usuários e serviços, não contra alguém que remove o cartão SD. Combine com criptografia de disco completo para ter proteção física.

Credenciais criptografadas do systemd com TPM

Em sistemas com systemd e um chip TPM 2.0, o systemd-creds criptografa um segredo para que ele só possa ser descriptografado naquela máquina e apenas para o serviço que o declara:

# Criptografa a senha, vinculada ao TPM desta máquina
echo -n 'YOUR_PASSWORD' | sudo systemd-creds encrypt --with-key=tpm2 \
  --name=mqtt-password - /etc/credstore.encrypted/mqtt-password
# /etc/systemd/system/mqtt-agent.service
[Unit]
Description=MQTT telemetry agent
After=network-online.target
Wants=network-online.target

[Service]
User=mqttsvc
LoadCredentialEncrypted=mqtt-password:/etc/credstore.encrypted/mqtt-password
Environment=MQTT_USERNAME=YOUR_USERNAME MQTT_CLIENT_ID=YOUR_CLIENT_ID
ExecStart=/usr/bin/python3 /opt/mqtt-agent/agent.py
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

O serviço lê o segredo descriptografado de um diretório privado em memória:

import os
import ssl
import paho.mqtt.client as mqtt

cred_dir = os.environ["CREDENTIALS_DIRECTORY"]
with open(os.path.join(cred_dir, "mqtt-password")) as f:
    password = f.read().strip()

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=os.environ["MQTT_CLIENT_ID"],
                     protocol=mqtt.MQTTv5)
client.username_pw_set(os.environ["MQTT_USERNAME"], password)
client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
client.connect("YOUR_BROKER_HOST", 8883, keepalive=60)
client.loop_forever()

Uma imagem de disco copiada é inútil em outra máquina, porque o TPM não vai liberar a credencial.

Comparação das opções de armazenamento

Método Plataforma Protege contra vazamento do firmware Protege contra cópia da flash Esforço
Fixo no firmware Qualquer Não Não Nenhum
NVS simples / arquivo de configuração ESP32 / Linux Sim Não Baixo
Criptografia da NVS mais criptografia de flash, Secure Boot ESP32 Sim Sim Médio, eFuses irreversíveis
Secure element ESP32, Linux Sim Sim, o mais forte para chaves Alto
Permissões de arquivo mais criptografia de disco Linux Sim Parcialmente Baixo a médio
systemd-creds com TPM Linux Sim Sim Médio

Credenciais na memória, em backups e em atualizações

O armazenamento criptografado protege a credencial em repouso, mas ela ainda precisa ser descriptografada na RAM para montar o pacote CONNECT. Alguns hábitos reduzem a exposição no restante do caminho:

  • Mantenha-a em um só lugar. Carregue a credencial uma única vez em um buffer pertencente ao módulo MQTT, em vez de copiá-la para strings globais, estruturas de configuração e objetos de diagnóstico.
  • Exclua-a dos diagnósticos. Core dumps, relatórios de falhas e envios remotos de logs nunca devem conter o armazenamento de credenciais. No Linux, mantenha o arquivo de credenciais fora dos conjuntos de backup e dos pacotes de suporte.
  • Não a faça passar pela nuvem. Um recurso de sincronização de configuração que envia as configurações do dispositivo ao seu backend deve ignorar totalmente os campos de credenciais.
  • Grave atualizações de forma atômica. Quando uma nova credencial chega durante a rotação, grave-a em um segundo slot e só faça a troca após uma conexão bem-sucedida, para que uma queda de energia não deixe o dispositivo com uma senha gravada pela metade.
  • Apague no descomissionamento. Apague o namespace da NVS ou o arquivo de credenciais como parte dos procedimentos de reset de fábrica e de descomissionamento.

Erros que vazam credenciais

  1. Imprimir a senha em logs de depuração ou em dumps de falha.
  2. Expô-la em uma página web do dispositivo "por conveniência", mesmo mascarada no HTML.
  3. Guardá-la em uma retained message MQTT ou enviá-la para um topic compartilhado.
  4. Deixar o modo de download via UART e o JTAG ativados em unidades de produção.
  5. Usar uma única credencial para a frota inteira, de modo que uma extração compromete tudo.
  6. Nunca fazer rotação, de modo que uma credencial vazada anos atrás ainda funciona.

O ponto 5 merece destaque. No ConnectMQ, cada client ID é vinculado às credenciais emitidas, então dê a cada dispositivo o seu próprio conjunto; uma senha extraída expõe então apenas um dispositivo, que você pode revogar e substituir com o processo descrito em como rotacionar credenciais MQTT. O isolamento de tenants significa que até as credenciais de um dispositivo comprometido só alcançam o seu próprio broker, e o bloqueio de IP após repetidas falhas de login atrasa atacantes que tentam adivinhar outras senhas. O conjunto mais amplo de controles está em boas práticas de segurança MQTT.

Comece a usar o ConnectMQ

Combine o armazenamento protegido no dispositivo com um broker MQTT gerenciado que cuida do TLS e da emissão de credenciais para você. Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito, e teste o armazenamento de credenciais do seu ESP32 ou Linux com um endpoint TLS real. O servidor MQTT público gratuito serve para protótipos rápidos, nunca para credenciais ou dados reais. Se você está começando no lado do hardware, o tutorial de MQTT com ESP32 é um bom ponto de partida, e o guia de broker MQTT na nuvem explica as opções de hospedagem.

Perguntas frequentes

A biblioteca Preferences do ESP32 é segura para senhas MQTT?

Somente se a criptografia da NVS e a criptografia de flash estiverem ativadas. Sem elas, a Preferences armazena os dados em texto claro na flash, que qualquer pessoa com acesso físico consegue copiar.

Preciso de um secure element para credenciais MQTT?

Nem sempre. Armazenamento criptografado com criptografia de flash e Secure Boot é adequado para muitos produtos; um secure element tem mais valor para identidade baseada em certificados ou implantações de alto valor.

Onde um gateway Linux deve guardar sua senha MQTT?

No mínimo em um arquivo 0600 pertencente à conta de serviço. Onde houver um TPM disponível, as credenciais criptografadas do systemd vinculam o segredo àquela máquina.

O TLS protege as credenciais armazenadas no dispositivo?

Não. O TLS protege as credenciais em trânsito. A proteção do armazenamento é uma camada separada, necessária no próprio dispositivo.

Artigos relacionados

Listas de Controle de Acesso (ACLs) no MQTT: Conceitos e Design

O que são as listas de controle de acesso MQTT, como brokers como o Mosquitto expressam regras de leitura e escrita por topic, como se comportam as operações negadas e como projetar namespaces de topics para manter a autorização simples.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.