Dominando a Arte da Segurança em Progressive Web Apps
Progressive Web Apps (PWAs) tornaram‑se o padrão de‑facto para oferecer experiências semelhantes a aplicativos na web aberta. Suas principais vantagens—capacidade offline, notificações push e instalabilidade—também introduzem novas superfícies de ataque que sites tradicionais raramente enfrentam. Este artigo aprofunda o ciclo de vida da segurança de uma PWA, combinando endurecimento em nível de rede, proteções em tempo de execução e boas práticas operacionais. Ao final, você terá um checklist aplicável a qualquer projeto, seja um simples leitor de notícias ou uma plataforma de comércio eletrônico complexa.
TL;DR: Proteja sua PWA com HTTPS, imponha CSP rigorosa, sandbox os service workers, valide todas as entradas e adote uma rotina contínua de monitoramento.
1. Camada de Transporte – A Primeira Linha de Defesa
1.1 Imponha HTTPS em Todo Lugar
Todos os navegadores modernos exigem HTTPS para o registro de service workers. Entretanto, alguns recursos (ex.: análises de terceiros) ainda podem ser carregados via HTTP, gerando alertas de conteúdo misto e abrindo brechas para ataques man‑in‑the‑middle (MITM).
Passos essenciais:
- Obtenha um certificado TLS confiável (Let’s Encrypt, Cloudflare, etc.).
- Redirecione todas as requisições
http://parahttps://via configuração do servidor. - Habilite HSTS (HTTP Strict Transport Security) para forçar os navegadores a usar HTTPS por um período predefinido.
# Exemplo de trecho NGINX
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Configurações TLS ...
}
Nota: O HSTS elimina ataques de downgrade, mas requer planejamento cuidadoso porque, uma vez definido, os navegadores recusarão conexões HTTP durante o período especificado.
1.2 Pinagem de Certificado (Opcional)
Para PWAs altamente sensíveis—bancários, registros de saúde—considere pinagem de certificado via Public Key Pinning Extension for HTTP (HPKP). Embora o HPKP esteja sendo descontinuado devido a riscos de implantação, você pode alcançar segurança semelhante com cabeçalhos Expect‑CT, que impõem Transparency de Certificados.
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/report"
2. Endurecimento do Service Worker
Service workers são o coração da capacidade offline de uma PWA. Eles rodam em uma thread de fundo com privilégios elevados, o que os torna alvos privilegiados de exploração.
2.1 Limitação de Escopo
Defina o scope mais restrito possível ao registrar um service worker. Isso impede que o worker intercepte requisições fora da área desejada.
navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
.then(reg => console.log('SW registrado com escopo:', reg.scope));
2.2 Verifique a Integridade com Subresource Integrity (SRI)
Se carregar o script do service worker de um CDN, proteja‑o com SRI para garantir que o código obtido corresponde ao hash esperado.
<script src="https://cdn.example.com/sw.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
2.3 Política de Segurança de Conteúdo para Service Workers
Uma CSP rigorosa pode impedir que o worker carregue scripts maliciosos ou se conecte a origens não desejadas.
Content-Security-Policy: script-src 'self' https://trusted.cdn.com;
connect-src 'self' https://api.example.com;
Dica: Use a diretiva
worker-src(suportada nos navegadores mais recentes) para listar explicitamente as origens permitidas para scripts de workers.
2.4 Gerenciamento de Estado e Validação de Cache
Nunca confie cegamente nas entradas de cache. Sempre valide a frescura das respostas armazenadas, especialmente para tokens de autenticação ou dados pessoais.
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (url.pathname.startsWith('/api/')) {
// Ignora o cache para dados dinâmicos
event.respondWith(fetch(event.request));
return;
}
// Estratégia padrão cache‑first para recursos estáticos
event.respondWith(
caches.match(event.request).then(cached => cached || fetch(event.request))
);
});
3. Proteções em Tempo de Execução – CSP, Permissões e Sandbox
3.1 CSP Completa
Uma CSP bem‑elaborada reduz o risco de Cross‑Site Scripting (XSS) e Injeção de Dados. Abaixo, um exemplo de política adaptada a uma PWA típica:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'sha256-XYZ' https://analytics.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com wss://socket.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
script-srcinclui um hash para scripts inline, evitandounsafe-inline.frame-ancestors 'none'desativa clickjacking.connect-srclista as APIs e endpoints WebSocket permitidos.
3.2 Permissions Policy (antiga Feature‑Policy)
Restrinja recursos poderosos do navegador que a PWA possa herdar inadvertidamente.
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()
3.3 Atributo Sandbox para Conteúdos Incorporados
Se sua PWA incorpora iframes de terceiros, sandbox‑e‑os para impedir a execução de scripts e navegação indevida.
<iframe src="https://maps.example.com"
sandbox="allow-scripts allow-same-origin"
loading="lazy"></iframe>
4. Autenticação & Autorização
4.1 Auth baseada em Token com JWT
Utilize JSON Web Tokens (JWT) para autenticação sem estado, mas nunca os armazene em localStorage—use cookies Secure, HttpOnly para mitigar roubos por XSS.
Set-Cookie: token=eyJhbGciOi...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
4.2 Rotação de Refresh Tokens
Implemente refresh tokens rotativos para limitar o impacto de um token comprometido.
- O cliente envia o refresh token.
- O servidor o valida e emite um novo access token e um novo refresh token.
- O refresh token antigo é invalidado no banco de dados.
4.3 Mitigação de CSRF
Mesmo com cookies SameSite, use tokens anti‑CSRF para requisições POST que alterem estado.
<input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
No servidor, verifique se o token corresponde à sessão.
5. Armazenamento Seguro de Dados
PWAs podem armazenar dados via IndexedDB, Cache API e Web Storage. Cada um tem considerações de segurança próprias.
| Armazenamento | Adequação | Dicas de Segurança |
|---|---|---|
| Cache API | Recursos estáticos, fallback offline | Cache apenas recursos imutáveis. Use nomes de cache versionados para remover dados obsoletos. |
| IndexedDB | Dados estruturados, preferências do usuário | Criptografe campos sensíveis no cliente usando a Web Crypto API. |
| LocalStorage / SessionStorage | Dados pequenos e não sensíveis | Evite guardar segredos. Qualquer script na página pode ler esses dados. |
5.1 Exemplo: Criptografando Dados no IndexedDB
async function encryptAndStore(key, value) {
const cryptoKey = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(value);
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
cryptoKey,
encoded
);
const db = await openDB('secure-store', 1, {
upgrade(db) { db.createObjectStore('secrets'); }
});
await db.put('secrets', { iv, ciphertext }, key);
}
6. Monitoramento, Auditoria e Resposta a Incidentes
Segurança não é uma configuração única; é um ciclo contínuo.
6.1 Varredura Automatizada
- Use OWASP ZAP ou Burp Suite para escanear XSS, CSRF e cabeçalhos inseguros.
- Integre auditorias Lighthouse ao pipeline CI/CD para garantir conformidade PWA.
6.2 Logging em Tempo de Execução
Capture erros do service worker e encaminhe‑os a um endpoint seguro para análise.
self.addEventListener('error', event => {
fetch('https://logs.example.com/collect', {
method: 'POST',
body: JSON.stringify({ message: event.message, stack: event.error.stack })
});
});
6.3 Playbook de Incidentes
- Detectar: Alerta disparado por tráfego anômalo ou relatórios de violação CSP.
- Conter: Revogar JWTs comprometidos, rotacionar chaves de API.
- Erradicar: Corrigir código vulnerável, atualizar cache do service worker.
- Recuperar: Implantar nova versão, monitorar recorrência.
- Post‑mortem: Documentar causa raiz, atualizar checklist de segurança.
7. Visão Geral Visual – Camadas de Segurança em uma PWA
flowchart TB
subgraph "Camada de Transporte"
H["HTTPS"]
S["HSTS"]
end
subgraph "Service Worker"
SW["Limitação de Escopo"]
CS["Validação de Cache"]
end
subgraph "Tempo de Execução"
CSP["Content Security Policy"]
PP["Permissions Policy"]
SAN["iFrames em Sandbox"]
end
subgraph "Autenticação e Dados"
JWT["Cookies Seguros"]
REF["Rotação de Refresh"]
ENC["Criptografia no IndexedDB"]
end
subgraph "Monitoramento"
SCAN["OWASP ZAP"]
LOG["Logging em Tempo Real"]
end
H --> SW --> CSP --> JWT --> SCAN
S --> SW
CS --> PP
PP --> ENC
LOG --> SCAN
O diagrama ilustra como cada controle de segurança se apoia no anterior, formando uma arquitetura de defesa em profundidade.
8. Checklist – Referência Rápida para uma PWA Segura
- Servir todo o conteúdo via HTTPS com HSTS habilitado.
- Registrar service workers com o escopo mais restrito possível.
- Aplicar Subresource Integrity para scripts carregados remotamente.
- Impor CSP rigorosa, incluindo
worker-srce hashes de script. - Usar Permissions‑Policy para desativar recursos de navegador não utilizados.
- Armazenar tokens de autenticação em cookies Secure e HttpOnly; jamais em localStorage.
- Rotacionar refresh tokens e validar tokens anti‑CSRF em requisições que alterem estado.
- Criptografar dados sensíveis no IndexedDB.
- Executar varreduras OWASP ZAP automatizadas em cada Pull Request.
- Configurar logging em tempo real de erros do service worker.
- Manter um playbook de resposta a incidentes atualizado.
9. Perguntas Frequentes
P1: PWAs precisam de Service Worker para segurança?
Não. Medidas como HTTPS, CSP e cookies seguros funcionam independentemente. Contudo, o Service Worker é onde a maioria dos ataques em tempo de execução ocorre, exigindo endurecimento adicional.
P2: Posso usar unsafe-inline em CSP para estilos?
Evite ao máximo. Prefira gerar hashes ou nonces para estilos inline, ou mova‑os para arquivos CSS externos.
P3: Com que frequência devo renovar certificados TLS?
Let’s Encrypt emite certificados de 90 dias; automatize a renovação. Para certificados auto‑assinados ou comerciais, limite a validade a, no máximo, 1 ano.
10. Conclusão
Progressive Web Apps desfocam a linha entre experiências nativas e web, oferecendo recursos poderosos que simultaneamente ampliam a superfície de ataque. Ao combinar segurança no transporte, restringir o escopo dos service workers, impor uma Política de Segurança de Conteúdo rigorosa e adotar práticas robustas de autenticação, você pode proteger sua PWA sem sacrificar desempenho.
Lembre‑se: segurança é uma jornada, não um destino. Mantenha dependências atualizadas, audite seu código regularmente e fique atento a ameaças emergentes. Com as práticas descritas aqui, sua PWA estará bem armada contra os ataques web mais comuns.