Voltar ao Blog
    Microfrontends

    Subresource Integrity em Microfrontends: Blindagem Essencial para sua Arquitetura

    Como implementar Subresource Integrity (SRI) em microfrontends para garantir segurança contra código malicioso, ataques a CDNs e modificações não autorizadas em módulos carregados dinamicamente.

    5 de junho de 20256 min

    Em arquiteturas modernas com Micro Frontends (MFE), especialmente aquelas que utilizam importmap ou System.import() com frameworks como single-spa, é comum carregar módulos JavaScript dinamicamente a partir de CDNs ou buckets públicos. No entanto, essa flexibilidade traz desafios significativos de segurança.

    🚨 O Desafio

    Carregamento Dinâmico

    • Módulos carregados em tempo de execução
    • Execução de código malicioso se arquivos forem comprometidos
    • Falta de verificação de integridade

    Ambientes Distribuídos

    • Múltiplos times e pipelines de CI/CD
    • Garantir integridade dos módulos se torna complexo
    • Coordenação difícil entre equipes

    CDNs e Buckets Públicos

    • Recursos hospedados em terceiros
    • Alvo de ataques ou modificações não autorizadas
    • Falta de controle sobre o conteúdo servido

    ✅ A Solução: Subresource Integrity (SRI) com Import Maps

    A recente introdução do campo "integrity" nos importmaps permite especificar hashes criptográficos para cada módulo, garantindo que apenas o código esperado seja executado pelo navegador. Essa funcionalidade já é suportada nativamente no Chrome e pode ser utilizada em outros navegadores com o auxílio de polyfills como o ES Module Shims.

    Exemplo de Import Map com SRI:

    <script type="importmap">
    {
      "imports": {
        "app": "https://cdn.example.com/[email protected]/index.js",
        "react": "https://cdn.example.com/[email protected]/index.js",
        "vue": "https://cdn.example.com/[email protected]/index.js"
      },
      "integrity": {
        "https://cdn.example.com/[email protected]/index.js": "sha384-abc123def456...",
        "https://cdn.example.com/[email protected]/index.js": "sha384-xyz789ghi012...",
        "https://cdn.example.com/[email protected]/index.js": "sha384-mno345pqr678..."
      }
    }
    </script>
    

    🔐 Como Gerar o Hash de Integridade

    Comando para Gerar SHA-384:

    cat index.js | openssl dgst -sha384 -binary | openssl base64 -A
    

    Exemplo Prático:

    # Gerar hash para um arquivo específico
    openssl dgst -sha384 -binary dist/app.js | openssl base64 -A
    
    # Resultado: sha384-abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567...
    

    Script Automatizado:

    #!/bin/bash
    # generate-sri.sh
    
    generate_sri() {
        local file=$1
        local hash=$(openssl dgst -sha384 -binary "$file" | openssl base64 -A)
        echo "sha384-$hash"
    }
    
    # Gerar hashes para todos os arquivos JS
    for file in dist/*.js; do
        echo "$(basename "$file"): $(generate_sri "$file")"
    done
    

    🛠️ Integração com CI/CD

    JSPM Generator

    Ferramentas como o JSPM Generator facilitam a geração automática de import maps com hashes de integridade, integrando-se perfeitamente aos pipelines de CI/CD.

    # Instalar JSPM Generator
    npm install -g @jspm/generator
    
    # Gerar import map com SRI
    jspm generate --integrity --map dist/
    

    GitHub Actions Example:

    # .github/workflows/build-and-deploy.yml
    name: Build and Deploy with SRI
    
    on:
      push:
        branches: [main]
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          
          - name: Setup Node.js
            uses: actions/setup-node@v3
            with:
              node-version: '18'
              
          - name: Install dependencies
            run: npm ci
            
          - name: Build application
            run: npm run build
            
          - name: Generate SRI hashes
            run: |
              # Gerar hashes para todos os arquivos JS
              for file in dist/*.js; do
                hash=$(openssl dgst -sha384 -binary "$file" | openssl base64 -A)
                echo "sha384-$hash" > "${file}.sri"
              done
              
          - name: Update import map
            run: |
              # Atualizar import map com hashes gerados
              node scripts/update-importmap.js
              
          - name: Deploy to CDN
            run: |
              # Deploy para CDN com arquivos e import map
              aws s3 sync dist/ s3://your-cdn-bucket/
    

    ⚠️ Casos Reais de Comprometimento

    Ataques a CDNs

    • 🚨 Polyfill.io: O recente ataque demonstrou como a falta de verificação de integridade pode levar à injeção de código malicioso em larga escala
    • 🚨 Bootstrap CDN: Histórico de ataques similares em CDNs populares
    • 🚨 jQuery CDN: Vulnerabilidades exploradas através de modificações não autorizadas

    Modificações Não Autorizadas

    • 🚨 Versões antigas de módulos sobrescritas inadvertidamente
    • 🚨 Vulnerabilidades introduzidas por mudanças não controladas
    • 🚨 Código malicioso injetado em ambientes de produção

    🛡️ Boas Práticas

    1. Utilize SRI em Todos os Módulos

    <!-- ✅ Bom: SRI em todos os módulos -->
    <script type="importmap">
    {
      "imports": {
        "app": "https://cdn.example.com/[email protected]/index.js",
        "vendor": "https://cdn.example.com/[email protected]/index.js"
      },
      "integrity": {
        "https://cdn.example.com/[email protected]/index.js": "sha384-abc123...",
        "https://cdn.example.com/[email protected]/index.js": "sha384-xyz789..."
      }
    }
    </script>
    

    2. Combine com Políticas de Segurança

    <!-- Content Security Policy com SRI obrigatório -->
    <meta http-equiv="Content-Security-Policy" 
          content="require-sri-for script; script-src 'self' https://cdn.example.com;">
    

    3. Automatize no Pipeline

    // scripts/update-importmap.js
    const fs = require('fs');
    const crypto = require('crypto');
    
    function generateSRI(filePath) {
      const content = fs.readFileSync(filePath);
      const hash = crypto.createHash('sha384').update(content).digest('base64');
      return `sha384-${hash}`;
    }
    
    function updateImportMap() {
      const importMap = {
        imports: {
          "app": "https://cdn.example.com/[email protected]/index.js"
        },
        integrity: {}
      };
      
      // Gerar hash para cada arquivo
      const files = ['dist/app.js', 'dist/vendor.js'];
      files.forEach(file => {
        const url = `https://cdn.example.com/${file}`;
        importMap.integrity[url] = generateSRI(file);
      });
      
      // Salvar import map atualizado
      fs.writeFileSync('dist/importmap.json', JSON.stringify(importMap, null, 2));
    }
    
    updateImportMap();
    

    🔧 Implementação Prática

    Single-SPA com SRI

    // main.js
    import { registerApplication, start } from 'single-spa';
    
    // Import map com SRI
    const importMap = {
      imports: {
        "react": "https://cdn.example.com/[email protected]/index.js",
        "vue": "https://cdn.example.com/[email protected]/index.js"
      },
      integrity: {
        "https://cdn.example.com/[email protected]/index.js": "sha384-abc123...",
        "https://cdn.example.com/[email protected]/index.js": "sha384-xyz789..."
      }
    };
    
    // Registrar aplicações com SRI
    registerApplication({
      name: 'react-app',
      app: () => System.import('react'),
      activeWhen: '/react'
    });
    
    registerApplication({
      name: 'vue-app', 
      app: () => System.import('vue'),
      activeWhen: '/vue'
    });
    
    start();
    

    Fallback para Navegadores Antigos

    <!-- ES Module Shims para suporte a SRI em navegadores antigos -->
    <script async src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js"></script>
    
    <script type="importmap">
    {
      "imports": {
        "app": "https://cdn.example.com/[email protected]/index.js"
      },
      "integrity": {
        "https://cdn.example.com/[email protected]/index.js": "sha384-abc123..."
      }
    }
    </script>
    

    📊 Monitoramento e Alertas

    Verificação de Integridade

    // Verificar integridade em tempo de execução
    function verifyIntegrity(url, expectedHash) {
      return fetch(url)
        .then(response => response.arrayBuffer())
        .then(buffer => {
          const hash = crypto.subtle.digest('SHA-384', buffer);
          return hash.then(hashBuffer => {
            const hashArray = new Uint8Array(hashBuffer);
            const hashBase64 = btoa(String.fromCharCode(...hashArray));
            return `sha384-${hashBase64}` === expectedHash;
          });
        });
    }
    
    // Uso
    verifyIntegrity(
      'https://cdn.example.com/[email protected]/index.js',
      'sha384-abc123...'
    ).then(isValid => {
      if (!isValid) {
        console.error('❌ Integridade comprometida!');
        // Implementar alertas ou fallbacks
      }
    });
    

    🚀 Benefícios da Implementação

    Segurança

    • Proteção contra código malicioso injetado
    • Verificação de integridade automática
    • Prevenção de ataques a CDNs

    Confiabilidade

    • Garantia de código válido em produção
    • Prevenção de modificações não autorizadas
    • Auditoria de integridade completa

    Compliance

    • Atendimento a padrões de segurança
    • Documentação de integridade para auditorias
    • Rastreabilidade de mudanças

    📋 Checklist de Implementação

    • Gerar hashes SRI para todos os módulos
    • Atualizar import maps com campos de integridade
    • Implementar CSP com require-sri-for
    • Automatizar geração no pipeline CI/CD
    • Configurar monitoramento de integridade
    • Implementar fallbacks para navegadores antigos
    • Documentar processo de atualização de hashes
    • Treinar equipe sobre boas práticas de SRI

    Este artigo apresenta uma medida essencial de segurança para arquiteturas de microfrontends. A implementação de Subresource Integrity protege contra ataques e garante que apenas código validado seja executado. Para discussões técnicas, implementações ou dúvidas sobre segurança em microfrontends, me encontre no LinkedIn ou GitHub.