Armazenamento de objetos
Onde guardar arquivos, com URLs assinadas e envio direto do navegador.
As decisões sobre arquivos são cinco: onde guardar, como receber, como entregar, como proteger e como organizar o ciclo de vida.
Onde guardar
| Opção | Bom para | Cuidados |
|---|---|---|
| Serviço de nuvem (S3, Cloud Storage, Azure Blob) | A maioria dos sistemas | Custo de saída de dados (transferência para a internet) |
| Compatíveis sem custo de saída (Cloudflare R2, Backblaze B2) | Muito download, como mídia e arquivos públicos | Recursos e regiões diferentes do S3 |
| Servidor próprio compatível com S3 (Ceph, SeaweedFS, Garage) | Infraestrutura própria, exigências de localização dos dados | Operar o armazenamento, inclusive a durabilidade |
| Disco do servidor | Arquivos temporários de processamento | Nunca como armazenamento definitivo |
| Banco de dados | Arquivos minúsculos e poucos, que precisam de transação com os dados | Banco e backups maiores |
Programe contra a API do S3: os SDKs funcionam com quase todos os serviços, trocando o endereço, como os exemplos da Implementação fazem.
Como receber arquivos
| Forma | Como funciona | Quando usar |
|---|---|---|
| Pela aplicação, em memória | A aplicação recebe o arquivo inteiro e depois envia | Arquivos pequenos e poucos; ainda assim, limite o tamanho |
| Pela aplicação, em fluxo | A aplicação repassa as partes conforme chegam | Quando precisa inspecionar ou transformar no caminho |
| Direto, com URL assinada por PUT | O navegador envia direto, com o tipo fixado | Arquivos sem limite rígido de tamanho |
| Direto, com POST e política | O navegador envia um formulário com condições assinadas: tipo, prefixo da chave, faixa de tamanho | Quando o tamanho precisa de limite (fotos, documentos) |
| Envio em partes (multipart upload) | O arquivo vai em partes, que podem ser reenviadas sozinhas | Arquivos grandes, acima de dezenas de MB, e conexões instáveis |
No teste do nível Conceito, repassar 300 MB pela aplicação custou 716 MB de memória em memória e 139 MB em fluxo; o envio direto não custa nada à aplicação.
Depois do envio direto, a aplicação não sabe o que chegou. Ela confere o objeto (existência, tamanho, tipo) antes de registrar, e pode processá-lo numa tarefa em segundo plano: gerar miniaturas, conferir se a imagem é mesmo uma imagem, procurar vírus.
Como entregar arquivos
| Forma | Quando usar | Cuidados |
|---|---|---|
| URL assinada de download | Arquivos privados: notas fiscais, documentos, anexos | Validade curta, gerada a cada acesso autorizado |
| CDN na frente de um bucket privado | Arquivos públicos muito acessados: imagens de produtos | A CDN acessa o bucket com credencial própria; o bucket continua privado |
| Bucket público | Quase nunca | Tudo o que for gravado lá fica exposto, inclusive por engano |
| Pela aplicação | Quando a autorização precisa ser conferida a cada byte, ou o arquivo é gerado na hora | A aplicação carrega o tráfego inteiro |
Como proteger
| Risco | Defesa |
|---|---|
| Upload de HTML ou SVG servido como página do seu domínio (XSS armazenado) | Tipo fixado na assinatura, download com Content-Disposition: attachment, arquivos de usuários num domínio separado |
| Arquivos enormes enchendo o armazenamento e a conta | POST com content-length-range, ou conferência do tamanho depois do envio |
Chaves adivinháveis (notas/1.pdf, notas/2.pdf) | Chave gerada pela aplicação, com identificador aleatório; autorização antes de gerar a URL |
| URLs assinadas compartilhadas e reutilizadas | Validade curta: minutos para envio, minutos a horas para download |
| Bucket público por engano | Bloqueio de acesso público na conta (S3 Block Public Access e equivalentes) |
| Credenciais na aplicação vazando | Papéis da nuvem (IAM) em vez de chaves fixas, com permissão só no bucket e nas operações necessárias |
| Arquivo com conteúdo malicioso | Conferir o tipo real pelo conteúdo, não pela extensão; antivírus para arquivos que outros usuários vão abrir |
Um domínio separado para os arquivos de usuários (como usercontent.exemplo.com) é a defesa mais forte contra XSS por upload: mesmo que um HTML seja aberto no navegador, ele não tem acesso aos cookies do domínio principal.
Ciclo de vida
| Configuração | Para quê |
|---|---|
| Classes de armazenamento (frequente, infrequente, arquivo) | Arquivos antigos e pouco lidos custam menos em classes mais frias |
| Regras de ciclo de vida | Mover para classes frias depois de N dias; apagar arquivos temporários; apagar envios em partes abandonados |
| Versionamento | Recuperar arquivos apagados ou sobrescritos por engano |
| Bloqueio de objeto (object lock) | Backups que nem um administrador consegue apagar antes do prazo, contra ransomware |
| Replicação entre regiões | Recuperação de desastres |
Os envios em partes que nunca foram concluídos ficam guardados e cobrados, invisíveis numa listagem comum. Uma regra de ciclo de vida que os apaga depois de alguns dias evita a surpresa na conta.
Resumo da decisão
- Armazenamento de objetos para os arquivos; o banco guarda só os dados sobre eles.
- Envio direto do navegador, com URL assinada que fixa o tipo, ou POST com política que também limita o tamanho.
- Bucket privado, com URLs assinadas de validade curta ou CDN com credencial própria.
- Download como anexo e domínio separado para arquivos de usuários.
- Chaves geradas pela aplicação, com autorização antes de cada URL.
- Regras de ciclo de vida, versionamento onde importa, e papéis da nuvem no lugar de chaves fixas.
O próximo nível mostra a geração de URLs de envio e de download nas cinco linguagens, com os SDKs oficiais.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Desenhar o upload de arquivos do meu sistema
Quero desenhar o envio e a entrega de arquivos no meu sistema. Pergunte quais arquivos são enviados, os tamanhos, quem pode ver cada um, se há processamento depois (miniaturas, antivírus) e qual nuvem ou armazenamento eu uso. Proponha: 1. A forma de envio, com o fluxo completo. 2. O que a assinatura fixa (tipo, tamanho, chave). 3. Como os arquivos são entregues (URL assinada, CDN), com as validades. 4. As defesas contra XSS por upload. 5. O que a tabela do banco guarda sobre cada arquivo.
Configurar um bucket com segurança
Quero configurar um bucket do zero, com segurança. Pergunte qual serviço eu uso e para que o bucket serve. Monte comigo: 1. O bloqueio de acesso público. 2. A permissão mínima para a aplicação, com papéis em vez de chaves fixas. 3. A regra de CORS para o envio direto do navegador. 4. O versionamento e as regras de ciclo de vida, inclusive para envios em partes abandonados. 5. A criptografia e os registros de acesso.
Escolher onde guardar arquivos
Estou escolhendo onde guardar os arquivos do meu sistema. Pergunte o volume, quanto é baixado por mês, se os arquivos são públicos ou privados, exigências de localização dos dados e se prefiro serviço gerenciado ou infraestrutura própria. Compare para o meu caso S3, Cloud Storage, Azure Blob, Cloudflare R2, Backblaze B2 e um servidor próprio compatível com S3, quanto a custo de armazenamento, custo de saída, recursos e operação. Recomende uma opção.