Teve um projeto, há uns anos, em que o produto já estava em campo, funcionando, vendendo bem, quando o time comercial recebeu uma pergunta de um cliente grande: “isso passou por algum teste de segurança?”. Silêncio na sala. O device tinha SSH aberto com senha padrão, um serviço de debug rodando em produção e a atualização de firmware não verificava assinatura nenhuma — bastava um arquivo com o nome certo em um pendrive. Não tinha sido decisão de ninguém. Simplesmente não tinha entrado na lista de prioridades até alguém de fora perguntar.
Isso é mais comum do que parece em Embedded Linux. O time resolve o hardware, resolve o BSP, resolve a aplicação — e segurança fica pra “depois”, que geralmente é nunca, porque o produto já embarcou e voltar lá custa caro. Se você está entrando nesse mundo agora ou herdou um projeto que nunca teve essa camada, aqui vai a ordem que eu sigo pra não se perder.
Primeiro: mapeie a superfície de ataque de verdade
Não adianta ler sobre TPM e secure boot antes de saber o que o seu dispositivo expõe. Liste, sem economia:
- Interfaces físicas acessíveis (UART, JTAG/SWD, USB, cartão SD)
- Serviços de rede ativos e suas portas (SSH, telnet, servidor web, MQTT, protocolos proprietários)
- Como o firmware chega no dispositivo (OTA, USB, cabo serial, nunca é atualizado)
- Que dados sensíveis o dispositivo guarda (chaves, credenciais de Wi-Fi, dados de usuário)
- Quem mais tem acesso ao dispositivo fisicamente (só você, ou qualquer pessoa que compre o produto)
Na prática, um attacker com acesso físico e um dispositivo sem nenhuma proteção de boot leva menos de uma hora pra extrair a flash inteira com um programador de US$ 20. Isso muda completamente o que vale a pena investir primeiro.
A cadeia de boot é a fundação, não um extra
Se o bootloader carrega qualquer kernel que estiver na partição, sem checar assinatura nenhuma, tudo que vier depois — sandboxing de container, firewall, hardening de aplicação — está construído em cima de areia. Um root filesystem lido e alterado por fora (retirando o cartão SD, montando em outra máquina) derruba qualquer defesa em nível de aplicação.
O caminho mínimo viável, na maioria dos SoCs modernos (i.MX, STM32MP, alguns da Rockchip), é: chave pública gravada em fusíveis (OTP) na fábrica, bootloader de primeiro estágio verifica assinatura do U-Boot, U-Boot verifica assinatura do kernel + device tree, e o rootfs vem com dm-verity ou similar pra detectar alteração. Isso não é exotismo de empresa grande — é suporte nativo na maioria das plataformas que você já usa, só precisa ser habilitado.
Vou dedicar um artigo inteiro só a secure boot porque o tema merece profundidade, mas se você só vai fazer uma coisa da sua lista essa semana, é essa.
O kernel e o rootfs que você escolheu importam
Yocto e Buildroot facilitam demais gerar uma imagem funcional — e também facilitam demais deixar passar um kernel de três anos atrás com uma dúzia de CVEs conhecidas. Eu já vi builds em produção usando uma versão de kernel que tinha patch de segurança disponível havia mais de 12 meses, simplesmente porque ninguém tinha automatizado o rebase.
Prática concreta: entre no seu local.conf (Yocto) ou na configuração do Buildroot e confira a versão do kernel e das bibliotecas críticas (openssl, busybox, glibc/musl). Rode uma checagem de CVE — o Yocto tem a classe cve-check pronta pra isso, é só habilitar:
INHERIT += "cve-check"
Isso não resolve tudo sozinho, mas te dá visibilidade do que você está carregando, o que já é mais do que a maioria dos projetos tem hoje.
Serviços de rede: desligue o que não usa
Regra que eu aplico sem exceção: se o serviço não é usado em produção, ele não sobe em produção. Telnet, servidores de debug, portas de desenvolvimento abertas por padrão em templates de BSP — tudo isso vira porta de entrada gratuita. E “vamos desligar depois” quase nunca acontece, porque não tem sprint dedicado a isso.
Uma prática simples que evita boa parte do problema: tenha um perfil de build de desenvolvimento e um de produção, com serviços, senhas e chaves de debug completamente diferentes — não a mesma imagem com uma flag “modo produção” que alguém pode esquecer de setar.
Atualização é parte da superfície de ataque, não só da manutenção
Se o mecanismo de update não verifica assinatura, integridade e não tem proteção contra rollback (voltar pra uma versão antiga vulnerável de propósito), você criou o canal de ataque mais direto que existe: convença o dispositivo de que seu firmware malicioso é uma “atualização legítima” e pronto. Já vi implementação de OTA cuidadosamente feita e mecanismo de rollback simplesmente esquecido — o que permite um invasor “atualizar” o dispositivo pra uma versão antiga com vulnerabilidade conhecida e explorá-la.
Uma ordem de prioridade honesta
Se eu tivesse que dar uma ordem de ataque pra um projeto que está começando do zero em segurança, seria essa:
- Secure boot (ou pelo menos verificação de assinatura no bootloader)
- Desligar serviços/interfaces de debug em builds de produção
- Atualização com verificação de assinatura e proteção antirollback
- Kernel e bibliotecas atualizadas, com checagem de CVE automatizada
- Storage sensível (chaves, credenciais) fora de texto plano no rootfs
Não é a lista mais sofisticada do mundo. É a lista que resolve os problemas que eu efetivamente vi comprometerem produtos reais.
Nos próximos artigos eu vou entrar fundo em cada um desses pontos — secure boot, criptografia em hardware limitado, proteção de firmware contra engenharia reversa. Se você tem um caso específico do seu projeto que não se encaixa direito nessa lista, é exatamente esse tipo de dúvida que vale trazer nos comentários ou no canal do FortShield — segurança embarcada tem muita regra geral e pouca receita de bolo.


