Teu progresso
0 / 83 módulos0%
Estágio 03 · 03-08
BloqueadoSecurity é tratado como "pessoa do time security cuida". Quando você é o time, você é a pessoa. E quando há time security, eles olham PRs reativamente, não escrevem o código com você. A maioria dos bugs reportados em bug bounty são triviais: SSRF em uploader, IDOR cruzando tenant, XSS em render de markdown, header de CORS errado, JWT alg: none, rate limit ausente em endpoint sensível.
Este módulo é AppSec aplicado: OWASP Top 10 (atual), Top 10 API, threat modeling (STRIDE), input validation, secrets, supply chain, AppSec pipeline (SAST/DAST/SCA), pentesting básico, secure SDLC. Você sai escrevendo código defensivo por default e revisando PRs com olho de atacante.
Ordenado por incidência:
Aplicações modernas viram APIs. Top 10 específico:
Sistemático: pra cada componente, pergunte:
Output: lista de threats, controles propostos, riscos aceitos.
Quando: design de feature nova, system review periódico, pre-launch.
Princípio: trust no input, valide em fronteira.
string quando é UUID).<, >, &, ", '.encodeURIComponent.dangerouslySetInnerHTML vira armadilha.Prevenção:
raw exige cuidado.eval; cuidado com $where e operators que aceitam função.Test: input com '; DROP TABLE-- etc., produção deve responder erro de validation, não erro de DB.
User envia URL → server faz request a ela. Server pode acessar recursos internos (metadata 169.254.169.254 em AWS, internal services).
Prevenção:
ssrf-req-filter ou implemente cuidado./orders/123 retorna pedido sem checar que 123 pertence ao user atual. Atacante itera IDs.
Prevenção:
Endpoint aceita objeto inteiro e atualiza:
await db.user.update(req.body); // user manda { role: 'admin' }
Prevenção:
strict() no Zod).Vimos em 02-13. Em apps API com JWT em header, CSRF é menor preocupação. Em cookie-based, mitigue (SameSite, CSRF tokens).
Lib: helmet (Express/Fastify), @fastify/helmet.
.env local + .env.example versionado (sem valores).Secret scanning: GitHub native, gitleaks, trufflehog. Roda em pre-commit + CI.
Em 2026, supply chain virou frente principal: SolarWinds (2020), Codecov (2021), Log4Shell (2021), 3CX (2023), xz-utils backdoor (2024). Defesa mudou de "atualizar deps" pra stack inteiro de attestation, signing, SBOM, provenance.
reqests em vez de requests, colorama malicioso.xz-utils 2024 — atacante ganhou trust por anos antes de injetar backdoor.Framework canônico (Google + OpenSSF). 4 níveis de garantia:
| Nível | Garantia | Como atinge |
|---|---|---|
| SLSA 1 | Build process documentado | Build script versionado, output identificável |
| SLSA 2 | Build provenance, version controlled | Build em CI versionado, provenance gerada |
| SLSA 3 | Build platform isolada, source verificável | Builder hardenizado, provenance autenticada |
| SLSA 4 | Two-party review, hermetic builds | Reproducible builds, two-person review obrigatório |
Em 2026, SLSA 3 é alvo realista pra prod sério; SLSA 4 é raro fora de Google/Cloud-native critical infra.
Sistema de assinatura sem gerenciamento de chaves persistentes. Padrão emergente:
cosign sign --identity-token $OIDC_TOKEN ghcr.io/me/img:tag.cosign verify --certificate-identity ... --certificate-oidc-issuer ....Resultado: assinatura tem provenance verificável (CI workflow X em GitHub repo Y assinou), sem PGP key management.
Inventário formal de dependências e suas versões. Formatos:
Geradores: Syft (Anchore, multi-formato), CycloneDX CLI, GitHub native (Dependency Graph).
Exemplo mínimo (CycloneDX):
{
"bomFormat": "CycloneDX", "specVersion": "1.5",
"components": [{"type":"library", "name":"react", "version":"19.1.0",
"purl":"pkg:npm/react@19.1.0"}]
}
Em produção 2026, SBOM gerado em CI, anexado a release, assinado com cosign, versionado.
Padrão pra provenance metadata (quem buildou, quando, com qual source, qual builder). Predicates: slsa-provenance, vuln-scan, test-result, sbom.
cosign attest --predicate provenance.json --type slsaprovenance ghcr.io/me/img@sha256:...
Permite chains: image foi buildada por GH Actions workflow X que rodou test suite Y com result Z, tudo verificável on-demand.
image: ghcr.io/me/api@sha256:abc... (não :latest, não :v1).cosign verify antes de pull em K8s (admission controller via Kyverno / OPA Gatekeeper / Connaisseur).Cruza com 03-04 (CI/CD pipeline implementa isso), 04-15 (OSS maintainers do outro lado).
Em pipeline: SAST barato em PR, DAST nightly.
Compliance acelera com infra que já incorpora controls (audit log, encryption at rest, RBAC, logs imutáveis).
GDPR/LGPD aparecem como compliance ("o que jurídico exige"). Privacy engineering é diferente: discipline de design que coloca privacy como restrição técnica primária, não atenuação posterior.
Princípios técnicos (não legais):
Patterns técnicos:
Tokenization de PII:
token ↔ value.Field-level encryption:
email_encrypted (não email). Decryption só em código que precisa exibir.pgcrypto ou app-level com KMS.Right to be forgotten (LGPD/GDPR Art. 17):
DELETE FROM users. É:
hash(salt + user_id)). Foreign keys continuam válidas, PII vai embora.Differential privacy:
differential-privacy, OpenDP.k-anonymity, l-diversity, t-closeness:
Data flow mapping:
Patterns de minimização concretos:
Strict-Transport-Security, SameSite=Strict, sem PII em cookie value.SHA256(email + salt)) em logs de evento. Original só no user record.Tools de privacy engineering:
Antipatterns comuns:
name = 'redacted'", quasi-identifiers (CEP+idade+gênero) podem re-id em datasets pequenos.NIST framework:
Runbooks pra incidentes comuns (data breach, DDoS, account takeover).
Layers:
Quando 1 camada falha, próxima ainda barra.
SBOM (Software Bill of Materials) virou compliance-checkbox em 2024-2026 — US Executive Order 14028, EU Cyber Resilience Act, NIST SSDF. Mas SBOM gerado uma vez e largado em S3 não vale nada. Operação real exige cinco coisas: (a) SBOM gerado no build, assinado, attestado; (b) ingestão em vulnerability scanner contínuo; (c) VEX statements pra distinguir CVE-presente de CVE-explorável; (d) policy gates em deploy bloqueando builds sem SBOM válida; (e) SBOM diff entre versões pra audit e root-cause de incidentes.
SBOM formats — escolha e trade-offs:
| Format | Originador | Strengths | Quando usa |
|---|---|---|---|
| CycloneDX | OWASP | Rich metadata (services, ML models, formulation, vulnerabilities inline), JSON-first | Default 2026 pra apps modernos; suporta VEX nativamente |
| SPDX | Linux Foundation, ISO/IEC 5962 | Padrão ISO; foco em license compliance | Compliance-driven (federal contracts US, EU CRA) |
| SWID | NIST IR 8060 | Tag pra SW asset tracking (já-instalado) | Inventário endpoint, não build-time |
CycloneDX 1.6+ é default 2026 — VEX statements integradas, melhor tooling, cobertura de ML/AI components.
Geração no build:
# Multi-stage build com SBOM gerado
FROM node:20 AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:20-slim
COPY --from=builder /app /app
WORKDIR /app
CMD ["node", "dist/server.js"]
# CI step — gerar + assinar SBOM
syft packages dir:. -o cyclonedx-json=sbom.cdx.json
cosign attest --predicate sbom.cdx.json --type cyclonedx \
--key env://COSIGN_KEY \
ghcr.io/myorg/logistics-api:${GITHUB_SHA}
syft (Anchore) é tool de fato pra discovery; alternativas: cdxgen, trivy sbom, Docker Scout.
Anatomia de um SBOM CycloneDX (excerpt):
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-...",
"metadata": {
"timestamp": "2026-04-15T10:00:00Z",
"tools": [{ "vendor": "anchore", "name": "syft", "version": "1.5.0" }],
"component": { "type": "application", "name": "logistics-api", "version": "2.3.1" }
},
"components": [
{
"type": "library",
"bom-ref": "pkg:npm/express@4.18.2",
"name": "express",
"version": "4.18.2",
"purl": "pkg:npm/express@4.18.2",
"hashes": [{ "alg": "SHA-256", "content": "..." }],
"licenses": [{ "license": { "id": "MIT" } }]
}
],
"dependencies": [
{ "ref": "logistics-api", "dependsOn": ["pkg:npm/express@4.18.2", "..."] }
]
}
purl (Package URL spec) é o identificador canônico cross-ecosystem. bom-ref interno; dependencies mapeia o grafo.
VEX statements — o que mata o ruído de scanner:
_.get e a CVE é em _.merge).VEX statuses (CycloneDX VEX vocab):
| Status | Significado | Exigência |
|---|---|---|
not_affected | Componente está mas vuln não pode ser triggered | Justification obrigatória (ver abaixo) |
affected | Vuln explorável; sem fix ainda | Anote workaround se houver |
fixed | Vuln existia mas foi patched | Aponte versão/commit do fix |
under_investigation | Triagem em andamento | Coloque deadline de re-evaluation |
Justifications válidas pra not_affected (NTIA-defined):
code_not_present: subcomponente vulnerável foi removido no tree-shake/build.code_not_reachable: dependency presente mas código vulnerável não é importado.requires_configuration: vuln só ativa com config X que você não usa.requires_dependency: precisa de outro componente Y que não está.requires_environment: só explora em runtime/OS específico.protected_by_compiler: bounds check / type system mata.protected_at_runtime: WAF / sandbox bloqueia.protected_at_perimeter: serviço não exposto externamente.protected_by_mitigating_control: control compensatório.VEX statement — exemplo CycloneDX:
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"vulnerabilities": [
{
"id": "CVE-2024-12345",
"source": { "name": "NVD" },
"ratings": [{ "severity": "high", "score": 7.5 }],
"affects": [{ "ref": "pkg:npm/lodash@4.17.21" }],
"analysis": {
"state": "not_affected",
"justification": "code_not_reachable",
"response": ["will_not_fix"],
"detail": "App uses only lodash.get and lodash.set; CVE-2024-12345 in _.merge prototype pollution path is not in execution path. Verified via dependency-tree analysis 2026-04-10."
}
}
]
}
Pipeline integrado — Logística stack:
# .github/workflows/sbom-pipeline.yml (excerpt)
- name: Generate SBOM
run: syft packages dir:. -o cyclonedx-json=sbom.cdx.json
- name: Sign + attest SBOM to OCI
run: |
cosign attest --predicate sbom.cdx.json --type cyclonedx \
--key env://COSIGN_KEY \
ghcr.io/myorg/api:${{ github.sha }}
- name: Scan against vuln DB
run: grype sbom:sbom.cdx.json -o json > scan.json
- name: Apply VEX filter
run: |
grype sbom:sbom.cdx.json \
--vex vex/our-statements.cdx.json \
--fail-on critical \
-o table
- name: Upload to dependency-track
run: |
curl -X POST "$DT_URL/api/v1/bom" \
-H "X-Api-Key: $DT_API_KEY" \
-F "project=$DT_PROJECT_UUID" \
-F "bom=@sbom.cdx.json"
Dependency-Track (OWASP) é o de-facto SBOM portal: ingesta SBOM, monitora CVEs continuamente, aceita VEX, dá API pra policy gates.
Policy gates em deploy:
kubectl apply ou terraform apply.package sbom.policy
deny[msg] {
comp := input.components[_]
comp.licenses[_].license.id == "GPL-3.0-only"
msg := sprintf("Forbidden license GPL-3.0-only in %s", [comp.name])
}
SBOM diff — auditoria de mudanças entre releases:
cyclonedx-cli diff sbom-v2.3.0.json sbom-v2.3.1.json mostra components added/removed/upgraded.Anti-patterns observados:
not_affected sem justification ou detail → audit reprova; alguém vai questionar em 6 meses sem ter contexto.cosign sign sem keyless OIDC → key management vira problema; use Sigstore + Fulcio + Rekor (timeline em 03-08 §2.14).Cruza com 03-08 §2.14 (supply chain layers — VEX é a camada operacional acima de SLSA), 03-04 §2.x (CI gates pra deploy block), 03-07 §2.18 (alert fatigue mitigada por VEX correto), 03-15 (incident response usa SBOM diff pra root cause).
OWASP Top 10 2025 substituiu a edição 2021 (revisão a cada 4 anos) e mantém Broken Access Control no #1 desde 2017 — não muda porque IDOR e missing function-level continuam endemicos. CSP migrou de domain whitelist (sempre incompleto) pra strict-dynamic + nonces; Trusted Types (Baseline 2024 em Chrome/Edge) elimina DOM XSS no source. CSRF virou problema 90% resolvido por SameSite=Lax default Chrome 2020+, mas Origin check em mutating endpoints fecha o gap. JWT continua sendo footgun: alg: none, algorithm confusion HS256/RS256, e localStorage XSS — três anti-patterns que aparecem em pen test de toda startup brasileira.
OWASP Top 10 2025 — categorias e foco operacional Logística:
| # | Categoria | Manifestação típica Logística |
|---|---|---|
| A01 | Broken Access Control | IDOR GET /orders/:id sem WHERE tenant_id; missing function-level em admin routes |
| A02 | Cryptographic Failures | TLS 1.3 mandatory; AES-256-GCM/ChaCha20; Argon2id default (OWASP rec 2025), bcrypt cost 12+, pbkdf2 600k iterations mínimo |
| A03 | Injection | SQLi (Drizzle/Prisma defaults safe), command injection, NoSQL Mongo $where, prompt injection LLM (cruza com 04-10) |
| A04 | Insecure Design | Missing rate limit, missing tenant isolation, no security review em design phase |
| A05 | Security Misconfiguration | Default creds, verbose errors em prod, S3 bucket public, debug endpoints expostos |
| A06 | Vulnerable Components | Dependabot/Renovate + Snyk/Socket; SBOM contínua (cruza com §2.20) |
| A07 | Auth Failures | Brute force sem backoff, session fixation, MFA bypass via SMS |
| A08 | Software/Data Integrity | Pipeline integrity (SLSA §2.14), CDN SRI, package signing Sigstore |
| A09 | Logging/Monitoring Failures | Missing audit log, sem SIEM ingest, sem alert em failed-auth spike |
| A10 | SSRF | Webhook URL aceitando http://169.254.169.254/... (AWS IMDS metadata leak credentials se IMDS v1) |
CSP 2026 — strict-dynamic + nonces + Trusted Types:
Content-Security-Policy:
default-src 'self';
script-src 'nonce-{RANDOM_PER_REQUEST}' 'strict-dynamic' https:;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://cdn.logistica.example.com;
connect-src 'self' https://api.logistica.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
report-to csp-endpoint;
Reporting-Endpoints: csp-endpoint="https://api.logistica.example.com/csp-report"
strict-dynamic elimina necessidade de listar domains externos — script com nonce válido pode carregar transitivamente. unsafe-inline em script-src defeats CSP (XSS aberto); só use em style-src se inevitável.
Trusted Types — DOM XSS killer (Baseline 2024 Chrome/Edge; Safari WIP):
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types myPolicy;
const policy = trustedTypes.createPolicy('myPolicy', {
createHTML: (input) => DOMPurify.sanitize(input)
});
element.innerHTML = policy.createHTML(userInput); // safe; raw string throws
Browser bloqueia innerHTML = rawString em runtime — força sanitização explícita via policy. Dev experience: console mostra violation no source line exato.
CSRF — SameSite=Lax default + Origin check em mutations:
// Fastify hook — Origin/Referer check em mutating requests
const ALLOWED_ORIGINS = new Set([
'https://logistica.example.com',
'https://app.logistica.example.com',
]);
fastify.addHook('onRequest', (req, reply, done) => {
const isMutation = ['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method);
if (isMutation) {
const origin = req.headers.origin || req.headers.referer;
if (!origin || !ALLOWED_ORIGINS.has(new URL(origin).origin)) {
return reply.code(403).send({ error: 'CSRF check failed' });
}
}
done();
});
SameSite=Lax (default Chrome 2020+) já mata 95% CSRF — POST cross-origin não envia cookie. SameSite=Strict pra cookies high-value (banking/payment). SameSite=None; Secure apenas pra cross-origin legitimate (third-party iframe consentido). Double-submit cookie pattern útil quando session em cookie + token em header (SPA + cookie auth combo). Synchronizer Token Pattern legacy mas ainda relevante pra forms server-rendered.
JWT pitfalls — três footguns que aparecem em pen test:
// CORRETO — algorithms hardcoded, nunca trust header
import jwt from 'jsonwebtoken';
const payload = jwt.verify(token, RSA_PUBLIC_KEY, {
algorithms: ['RS256'], // BLOQUEIA alg:none + HS256 confusion
issuer: 'logistica-auth',
audience: 'logistica-api',
maxAge: '15m',
});
alg: none attack (clássico ainda vivo em libs novos): library aceita JWT sem signature. Hardcode algorithms: ['RS256'] em verify SEMPRE.localStorage: qualquer 3rd party script (analytics, tag manager) lê via XSS. Use HttpOnly cookie pra SPA. Authorization Bearer OK pra mobile (sem XSS vector via 3rd party scripts).kid header rotation: enable múltiplas signing keys; rotate monthly sem invalidar tokens existentes.Rate limit — patterns Logística (cruza com 02-11 §2.13):
| Layer | Implementação | Quando |
|---|---|---|
| Per-IP | nginx/Cloudflare | Anti-DoS basic, pre-auth |
| Per-user | Redis sliding window | Post-auth, fairness entre tenants |
| Per-endpoint | Redis namespace por route | Write endpoints (POST /orders) stricter que reads |
| Adaptive tier | Redis + tenant config | Premium 1000 req/min vs free 100 req/min |
| Failed-auth backoff | Redis counter + TTL exp | 5 fail logins → exponential backoff per (IP, username) |
Headers de segurança production-ready:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Permissions-Policy: geolocation=(self), camera=(), microphone=()
Referrer-Policy: strict-origin-when-cross-origin
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
HSTS 2 anos com preload registra domain em browser preload list (lock-in). COOP+COEP isola origin pra habilitar SharedArrayBuffer e WebAssembly threads. X-Frame-Options: DENY legacy mas Safari ainda honra; CSP frame-ancestors 'none' é replacement moderno.
Logística applied stack:
@fastify/helmet (CSP + HSTS + COOP + COEP defaults).SameSite=Lax default + Origin check em mutating endpoints.Content-Security-Policy-Report-Only em staging → Content-Security-Policy enforce em prod após 1 semana sem violations relevantes no endpoint de report.(IP, tenant_id) + tier premium.Pen test — focus areas Logística:
GET /orders/<id> de tenant B. Defesa: Postgres RLS + integration test que prova bloqueio./orders com cookie da vítima; Origin check bloqueia.http://169.254.169.254/latest/meta-data/ (AWS IMDS v1 leak credentials); use IMDS v2 + URL allowlist + DNS resolve check.Anti-patterns observados:
localStorage em SPA (qualquer 3rd party script lê via XSS).alg: none accepted em JWT verify (library defaults; ALWAYS specify algorithms).SameSite=None cookie sem Secure flag (Chrome reject silently).unsafe-inline em script-src (defeats CSP completely).strict-dynamic (sempre incompleto, bypass via JSONP/redirect em domain whitelisted).WHERE tenant_id filter (backend trust em frontend-supplied tenant id).preload (browser doesn't lock-in domain; primeiro request HTTP vulnerável a SSL strip).Cruza com 02-13 (auth — JWT + OAuth2 + refresh rotation), 02-09 (Postgres RLS multi-tenant), 02-11 (Redis rate limit sliding window), 03-15 (incident response — security incident playbook), 04-10 (LLM prompt injection cobre OWASP A03).
NIST SP 800-207 (2020) formalizou Zero Trust Architecture — every request authenticated + authorized, "never trust, always verify". O modelo antigo (perimeter security: VPN + firewall, confiança plena dentro da rede) cai porque breach lateral movement é trivial uma vez dentro. Google BeyondCorp (2014) foi pioneer; em 2026 é default cloud-native enterprise. Cinco pilares: identity (workload + user), device posture, network, application, data. Misconception comum: "zero trust = VPN replacement" — reality é framework abrangente que muda como cada componente verifica, não só o edge. Adoção operacional 2026 ancora em SPIFFE/SPIRE (CNCF graduated 2022) pra workload identity e service mesh (Linkerd 2.16+, Istio 1.23+, Cilium 1.16+) pra mTLS automático pod-to-pod.
Workload identity — SPIFFE / SPIRE:
spiffe://logistica.example.com/ns/orders/sa/orders-api.mTLS workload-to-workload — confidentiality + authenticity intra-cluster:
mTLS faz client + server apresentarem certificates e ambos verificarem — bloqueia lateral movement post-breach. Implementar mTLS app-level em cada serviço é boilerplate massivo; service mesh delega ao sidecar proxy de forma transparent.
Service mesh comparison 2026:
| Mesh | Architecture | mTLS | Performance | Best fit |
|---|---|---|---|---|
| Istio | Envoy sidecar | Auto | Heavy (~5-10ms p99 added) | Enterprise; many features |
| Linkerd | Rust micro-proxy | Auto | Light (~1-2ms added) | Simplicity; CNCF graduated |
| Cilium Service Mesh | eBPF-based | Auto | Light (kernel-level) | High-perf; replacing iptables |
| AWS App Mesh | Envoy managed | Auto | Heavy | AWS-native, simpler ops |
| Consul Connect | Envoy/built-in | Auto | Medium | HashiCorp ecosystem |
Linkerd setup (caminho mais simples, Rust micro-proxy):
# Install Linkerd CLI + check cluster
linkerd install --crds | kubectl apply -f -
linkerd install | kubectl apply -f -
linkerd check
# Inject sidecar to namespace
kubectl annotate namespace logistica linkerd.io/inject=enabled
kubectl rollout restart deployment -n logistica
# Verify mTLS
linkerd viz check
linkerd viz top deployment/orders-api -n logistica
Auto mTLS pod-to-pod transparente; Linkerd emite SPIFFE ID por pod. Latency overhead ~1-2ms p99 (Rust micro-proxy vs Envoy C++ Istio).
Istio AuthorizationPolicy (cross-service authz, default-deny):
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: orders-api-allowlist
namespace: logistica
spec:
selector:
matchLabels:
app: orders-api
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/logistica/sa/web-frontend"
- "cluster.local/ns/logistica/sa/orders-worker"
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/orders/*"]
Apenas ServiceAccounts listadas chamam orders-api; default-deny no resto. mTLS sozinho criptografa mas não autoriza — sem AuthorizationPolicy qualquer pod chama qualquer pod.
Network Policies K8s-native (L3/L4) + Cilium L7:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: orders-api-isolation
namespace: logistica
spec:
podSelector:
matchLabels:
app: orders-api
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector:
matchLabels:
app: web-frontend
ports:
- protocol: TCP
port: 3000
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
K8s default só especifica a API — exige CNI (Calico, Cilium) pra enforce. Cilium 1.16+ adiciona eBPF + L7 policies (HTTP path filter, gRPC method) — kernel-level, sem sidecar.
Logística zero trust applied stack:
web-frontend chama orders-api; só orders-worker chama payments-api.sslmode=verify-full + IAM-based auth (RDS IAM, Cloud SQL IAM) ou per-app credentials rotacionadas.Zero trust user-side (BeyondCorp model):
Anti-patterns observados (10 itens):
kube-system, linkerd, istio-system).Cruza com 03-03 (K8s NetworkPolicies), 02-13 (auth user-side OAuth2 + JWT), 03-08 §2.21 (OWASP applied), 04-08 (services — mesh requirement aparece em escala), 03-04 (CI/CD — cert rotation pipeline).
O backdoor xz/liblzma (CVE-2024-3094, Mar/2024) deixou o custo de não ter supply chain security mensurável: maintainer comprometido, payload em release tarball, escapou de revisão por 2 anos. Resposta da indústria 2024-2026 consolidou stack: SLSA v1.0 (framework de níveis de integridade de build), sigstore (assinatura keyless via OIDC + transparency log), npm provenance (default para trusted publishers), dependency-track + VEX (consumo de SBOM com supressão de falsos positivos), GUAC (graph DB para incident response). Esta seção cobre implementação production 2026 — não conceito.
SLSA (Supply-chain Levels for Software Artifacts) v1.0 estável Q4/2023. L1-L3 framework completo; L4 ainda em draft (Track Build expandida com hermetic + reproducible).
| Level | Requisito core | Verifica |
|---|---|---|
| L1 | Provenance existe (build documenta como foi feito) | Existe metadata |
| L2 | Provenance assinada pelo build platform | Não foi adulterada |
| L3 | Hosted build platform + isolated runner + tamper-resistant | Build não pode ser influenciado por outros builds |
| L4 (draft) | Hermetic + reproducible builds | Bit-for-bit determinístico, sem network ad-hoc |
Em 2026 a baseline production é L3 — e GitHub Artifact Attestations (GA Q4/2024) entrega L3 turnkey via actions/attest-build-provenance. Claim L3 sem isolated builder = false claim auditável.
Stack CNCF graduated Q4/2023:
Keyless = zero key management. Identidade do signer é o OIDC issuer + workflow path. Verificação não checa "esta chave assinou" mas "este workflow neste repo assinou".
# .github/workflows/release.yml
name: release
on:
push:
tags: ['v*']
permissions:
id-token: write # OIDC token para Fulcio
contents: read
attestations: write
packages: write
jobs:
build-sign:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: sigstore/cosign-installer@v3.7.0
with:
cosign-release: 'v2.4.1'
- name: Build container
run: docker build -t ghcr.io/org/app:${{ github.sha }} .
- name: Push image
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker push ghcr.io/org/app:${{ github.sha }}
- name: Sign image keyless
env:
COSIGN_EXPERIMENTAL: "1"
run: |
cosign sign --yes ghcr.io/org/app:${{ github.sha }}
# Turnkey SLSA L3 build provenance (GA Q4/2024)
- uses: actions/attest-build-provenance@v2
with:
subject-name: ghcr.io/org/app
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
Verificação consumer-side:
# Verifica assinatura + identidade do signer
cosign verify ghcr.io/org/app@sha256:abc... \
--certificate-identity "https://github.com/org/repo/.github/workflows/release.yml@refs/tags/v1.2.3" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
# Verifica build provenance (SLSA L3)
gh attestation verify oci://ghcr.io/org/app@sha256:abc... \
--owner org \
--predicate-type https://slsa.dev/provenance/v1
Falha de verificação aborta deploy. K8s admission policy via sigstore/policy-controller faz isso no cluster.
# package.json: trusted publishing configurado em npmjs.com → GitHub Actions
npm publish --provenance --access public
Workflow GitHub Actions com id-token: write gera attestation in-toto, registra em Rekor, npmjs.com exibe badge "Provenance" linkando ao workflow exato. Consumer verifica:
npm audit signatures # verifica todas dependências assinadas
Em 2026, publicar pacote npm sem --provenance é signal negativo — consumers não conseguem auditar origem.
Pipeline de SBOM consumption production:
# CI: gera SBOM + envia para dependency-track
syft ghcr.io/org/app:latest -o cyclonedx-json > sbom.json
curl -X POST "$DT_URL/api/v1/bom" \
-H "X-Api-Key: $DT_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "project=$PROJECT_UUID" \
-F "bom=@sbom.json"
Dependency-track faz CVE matching contínuo (NVD + GitHub Advisory + OSS Index), license scanning, dependency graph, alerta quando nova CVE aparece em versão deployada.
OpenVEX 0.2.0 (Q1/2024) statement YAML — "esta CVE não se aplica ao meu build":
# vex/CVE-2024-12345.openvex.yaml
"@context": "https://openvex.dev/ns/v0.2.0"
"@id": "https://example.com/vex/CVE-2024-12345"
author: "security@org.com"
timestamp: "2026-04-15T10:00:00Z"
statements:
- vulnerability:
name: "CVE-2024-12345"
products:
- "@id": "pkg:oci/app@sha256:abc..."
status: "not_affected"
justification: "vulnerable_code_not_in_execute_path"
impact_statement: "Função vulnerável em libfoo/parse() não invocada; só usamos libfoo/encode()."
Trivy consome VEX:
trivy image --vex ./vex/ ghcr.io/org/app:latest
CSAF VEX vem de upstream vendors (Red Hat, SUSE) — consumir reduz alert fatigue. Sem VEX, dependency-track gera centenas de alerts/semana → time ignora todos → CVE real escapa.
Graph DB que liga artifacts ↔ source ↔ vulnerabilities ↔ deployments. Ingest contínuo de SBOMs + attestations + CVE feeds:
guacone collect files ./sboms/
guacone collect files ./attestations/
# Query incident response: "quais imagens em prod têm CVE-X?"
guacone query vuln CVE-2024-3094
# → lista images, deployments, namespaces afetados
Em incident response (xz-style), GUAC responde em segundos o que sem ele leva dias de spreadsheet manual.
CI build: GitHub Actions com id-token: write → docker build → cosign sign keyless → actions/attest-build-provenance (SLSA L3) → npm publish --provenance para SDK packages. SBOM via Syft enviada a dependency-track self-hosted. VEX statements em vex/ directory consumidos por Trivy + dependency-track. K8s admission via sigstore-policy-controller bloqueia images sem attestation com identidade esperada. GUAC instance ingere SBOMs + attestations diariamente para incident response queries. Resultado: cada container em prod tem cadeia auditável até commit + workflow + signer OIDC, e CVE alerts são acionáveis (VEX suprime ruído).
npm publish sem --provenance em 2026 — consumers não auditam, sinal negativo.curl, npm install sem lockfile) — não-reproduzível, L4 falha.--certificate-identity (só checa "tem assinatura") — atacante assina com qualquer OIDC válido.Cruza com 03-08 §2.14 (supply chain intro), §2.20 (SBOM lifecycle + VEX intro), §2.21 (OWASP applied), 03-02 §2.22 (Wolfi + cosign + Trivy CI integration), 03-04 (CI/CD — Artifact Attestations as build gate), 03-03 (K8s admission validando attestations via sigstore-policy-controller), 04-15 (OSS maintainership — npm provenance impact em maintainers), 02-17 §2.20 (mobile security — App Attest iOS + Play Integrity Android pra device attestation), 04-15 §2.20 (OSS supply chain post-XZ + EU CRA + npm provenance + Sigstore).
Você precisa, sem consultar:
Hardening de Logística v1 com pipeline AppSec real.
THREAT-MODEL.md: threat → mitigation → status.orders como última linha.strict() em Zod.DOMPurify server-side).eval, dangerouslySetInnerHTML sem allowlist, raw SQL).PENTEST.md cada tentativa, resultado, fix.DELETE /me (right to be forgotten LGPD): anonimiza dados pessoais, mantém referências business (orders ficam mas customerName vira "Anônimo").Server exposto identificando versão.THREAT-MODEL.md).DELETE /me mostrando anonimização./admin/api/v1/.env) que loga tentativa.Threshold de Maestria
Acerte todas as 5 pra marcar o módulo como concluído. Sem pressa, sem timer. Tudo fica salvo no teu navegador.
Q1Por que JWT em `localStorage` é antipadrão crítico em SPA?
Q2Em CSP 2026, por que `strict-dynamic` + nonces é superior a domain whitelist tradicional?
Q3Qual o papel de VEX (Vulnerability Exploitability eXchange) statements em SBOM consumption?
Q4Em SLSA framework, qual a diferença entre L1 e L3?
Q5Por que SSRF é particularmente perigoso em AWS sem IMDSv2?
Destrava
03-08 é prereq dos seguintes módulos: