📬 Toda semana, um resumo de segurança, Clean Code e IA no seu e-mail Inscreva-se →

SDLC para Sistemas Embarcados: Adaptando o Ciclo de Desenvolvimento para Hardware Limitado

Já vi projeto de sistema embarcado passar por levantamento de requisitos, design, desenvolvimento e teste inteiros sem ninguém perguntar como o firmware seria atualizado depois que o produto estivesse em campo. A pergunta só apareceu quando o dispositivo já estava em produção, um bug apareceu e a resposta foi “a gente troca a flash na mão, dispositivo por dispositivo”. Com dez unidades isso é chato. Com dez mil, é um projeto de recall que ninguém orçou.

Esse tipo de furo não acontece porque o time é ruim. Acontece porque o SDLC que a maioria aprende é pensado para aplicação rodando em servidor ou navegador — algo que você atualiza com um git push e um deploy. Sistema embarcado quebra essa premissa em quase todas as fases, e se você não adaptar o processo para essa realidade, a segurança (e a própria manutenibilidade do produto) fica sempre para depois.

Já tratei aqui no blog como integrar segurança em cada fase do SDLC de forma geral, e também por onde começar em segurança de Embedded Linux na ponta mais técnica de boot chain e superfície de ataque. Este artigo é o meio de campo entre os dois: como o próprio ciclo de desenvolvimento — cada fase dele — muda quando hardware entra na equação.

O que é diferente em embarcados (e por que isso importa)

Quatro restrições que simplesmente não existem (ou existem bem menos) em software convencional:

  • Recurso é finito e conhecido de antemão. Processador, RAM e energia são fixos desde a escolha do SoC. Uma rotina de criptografia que “só” consome 200 KB de RAM pode inviabilizar o projeto inteiro se seu MCU tem 256 KB no total.
  • Hardware amplia a superfície de ataque. UART exposta, JTAG sem proteção, barramento SPI acessível — cada interface física é um vetor que simplesmente não existe numa aplicação web.
  • Atualizar em campo é caro ou impossível. Ao contrário de um servidor, você não faz apt upgrade num medidor de energia instalado há três anos dentro de uma parede.
  • Falha tem consequência física. Em automotivo e industrial, uma falha de segurança não é só vazamento de dado — pode ser motor travando ou válvula não fechando.

Essas quatro coisas juntas significam que um SDLC adaptado para embarcados não é o SDLC genérico com um capítulo extra sobre hardware. É um processo em que cada fase precisa responder a essas restrições explicitamente.

Fase por fase: o que muda de verdade

1. Levantamento de requisitos

Aqui é onde o erro do início deste artigo nasce. Requisito funcional (o que o dispositivo faz) é o de sempre — monitorar, controlar, comunicar. O que costuma faltar é o requisito não-funcional específico de embarcado:

  • Qual o orçamento de energia e de memória para segurança? (Se você não reservar isso agora, na fase de desenvolvimento não vai ter espaço.)
  • Como o dispositivo vai ser atualizado depois que estiver em campo — e o que acontece se a atualização falhar no meio?
  • Que certificação ou norma se aplica (automotivo tem uma; dispositivo médico, outra; IoT residencial, praticamente nenhuma obrigatória, o que é seu próprio risco).

Se “estratégia de atualização” não é uma pergunta respondida no levantamento de requisitos, ela vira um problema resolvido às pressas na fase de manutenção — com o produto já vendido.

2. Design e arquitetura

É aqui que entra modelagem de ameaça específica de hardware: extração de firmware via debug port, interceptação de barramento, manipulação de sensor. Não adianta desenhar a arquitetura de software e “depois” pensar em secure boot — a cadeia de confiança (chave gravada em fusível na fábrica → bootloader assina o próximo estágio → kernel assina o rootfs) precisa ser parte da arquitetura desde o início, porque muda decisão de SoC, de memória e até de fornecedor.

Defesa em profundidade aqui significa combinar camada de hardware (secure boot, TPM ou elemento seguro) com camada de software (sandboxing, princípio do menor privilégio) — nenhuma das duas sozinha resolve.

3. Desenvolvimento

A prática de validar toda entrada de usuário que já vale para qualquer software fica mais crítica em ambiente com recurso restrito, porque o efeito colateral de um buffer overflow em firmware é diferente de uma exceção capturada numa API:

/* ruim: confia no tamanho recebido do barramento serial */
void processar_pacote(uint8_t *buffer, uint16_t tamanho) {
    memcpy(destino, buffer, tamanho); /* sem checar limite de destino */
}

/* melhor: valida contra o buffer real antes de copiar */
void processar_pacote(uint8_t *buffer, uint16_t tamanho) {
    if (tamanho > sizeof(destino)) {
        registrar_erro(ERR_PACOTE_INVALIDO);
        return;
    }
    memcpy(destino, buffer, tamanho);
}

Parece óbvio escrito assim, mas em código C de firmware, sem os limites de linguagens gerenciadas, esse tipo de checagem que “todo mundo sabe que precisa fazer” é exatamente o que fica de fora quando o prazo aperta.

4. Testes, verificação e validação

Teste de sistema embarcado precisa cobrir hardware e software junto — e isso significa simular ataque real no ambiente do dispositivo, não só rodar um linter no código. Análise estática de firmware, teste dinâmico simulando falha de comunicação, e validação de protocolo (MQTT, CAN, Modbus, o que for) verificando se autenticação e criptografia estão de fato ativas — não só presentes na especificação.

Um ponto que vale ser honesto: teste de hardware-software integrado custa tempo e as vezes exige bancada física, não só CI rodando em nuvem. Isso não é desculpa para pular a etapa — é motivo para planejar esse tempo desde a fase de requisitos, não descobrir isso no fim.

5. Implantação, operação e manutenção

Atualização OTA (over-the-air) segura é o item que mais separa projeto embarcado maduro do amador: firmware assinado, verificação antes de aplicar, e principalmente proteção contra rollback — porque um invasor “atualizando” seu dispositivo para uma versão antiga e vulnerável é um ataque real, documentado, e simples de executar se ninguém pensou nisso.

Some a isso monitoramento remoto (para detectar comportamento anormal sem precisar de acesso físico) e um plano de resposta a incidente que já preveja: “e se o dispositivo não puder ser atualizado remotamente, qual o plano B?”.

Frameworks que ajudam a não reinventar a roda

Não é preciso criar processo do zero. Existem referências prontas para se apoiar: o OWASP IoT Top 10 lista as vulnerabilidades mais recorrentes em dispositivo conectado; FIPS estabelece requisito de segurança para módulos de criptografia; Common Criteria dá uma base internacional para avaliar segurança de produto. Nenhum desses substitui bom senso de engenharia, mas evitam que você comece do zero numa modelagem de ameaça que várias pessoas já fizeram antes.

O ponto central

SDLC para sistema embarcado não é o processo comum com um adendo de hardware — é o mesmo processo em que cada fase carrega uma pergunta extra: isso funciona com o recurso que eu realmente tenho, e isso sobrevive ao fato de que eu não vou conseguir corrigir isso com um deploy amanhã de manhã? Se a resposta para as duas é sim em todas as fases, o resto — ferramenta, framework, certificação — é implementação.

Se você trabalha com Embedded Linux no dia a dia, vale complementar este artigo com o guia de segurança em Embedded Linux para a parte mais prática de boot chain e superfície de ataque. E se ficou alguma dúvida sobre uma fase específica do seu projeto que não se encaixou nessa lista, é exatamente esse tipo de caso concreto que vale trazer nos comentários ou no canal do FortShield.

Leandro Rosendo Candido

Leandro Rosendo Candido

Engenheiro de Computação, mestre pela USP, 10+ anos com Embedded Linux. Escreve e grava sobre segurança, Clean Code e IA aplicada à programação.

Rolar para cima