O hardening de segurança em BaaS é um conjunto de controles em camadas — CLPs, ACLs e disciplina de chaves — que fecha as brechas com que um backend nasce. Backends nascem permissivos de propósito: classes abertas e schemas graváveis pelo cliente fazem o protótipo voar. O hardening é a passada deliberada que inverte esses defaults antes do lançamento — e é um checklist curto e conhecido, não um projeto de pesquisa.
Principais pontos
| Pergunta | Resposta |
|---|---|
| O que é | A passada pré-lançamento que tranca permissões de classe, ACLs, chaves e schema |
| As camadas | CLPs guardam a classe → ACLs guardam a linha → campos protegidos guardam a coluna |
| A regra absoluta | A master key ignora tudo — ela nunca sai do servidor |
| O caminho privilegiado | Funções de Cloud Code são a porta auditada para escritas sensíveis |
| O que as chaves não são | App IDs e client keys são identificadores, não segredos — planeje assim |
O default endurecido, em código
A metade por objeto da história — uma ACL restrita ao dono, em camada sob uma classe trancada:
// JavaScript / Node.js — Back4app JS SDK
// Per-object ACL: the owner reads and writes, a moderator role reads,
// the public gets nothing — layered under the class-level permissions
const note = new Parse.Object('Note');
note.set('body', 'quarterly numbers');
const acl = new Parse.ACL(Parse.User.current()); // owner: read + write
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setRoleReadAccess('moderator', true); // role: read only
note.setACL(acl);
await note.save();
// The class gate above it is schema config, set in the dashboard:
// find/get: requiresAuthentication · create: authenticated · addField: nobody // Flutter / Dart — Back4app Flutter SDK
// Per-object ACL: owner read/write, moderator role read, public nothing
final note = ParseObject('Note')..set('body', 'quarterly numbers');
final acl = ParseACL(owner: await ParseUser.currentUser()); // owner: r+w
acl.setPublicReadAccess(allowed: false);
acl.setPublicWriteAccess(allowed: false);
acl.setReadAccess(userId: 'role:moderator', allowed: true); // role: read
note.setACL(acl);
await note.save();
// The class gate above it is schema config, set in the dashboard:
// find/get requiresAuthentication, create authenticated, addField off // iOS / Swift — Back4app Swift SDK
// Per-object ACL: owner read/write, moderator role read, public nothing
var note = Note()
note.body = "quarterly numbers"
var acl = ParseACL()
acl.publicRead = false
acl.publicWrite = false
if let user = User.current {
acl.setReadAccess(user: user, value: true) // owner: read
acl.setWriteAccess(user: user, value: true) // owner: write
}
acl.setReadAccess(roleName: "moderator", value: true) // role: read only
note.ACL = acl
note.save { result in
if case .failure(let error) = result { print(error) }
} // Android / Kotlin — Back4app Android SDK
// Per-object ACL: owner read/write, moderator role read, public nothing
val note = ParseObject("Note").apply { put("body", "quarterly numbers") }
val acl = ParseACL(ParseUser.getCurrentUser()) // owner: read + write
acl.publicReadAccess = false
acl.publicWriteAccess = false
acl.setRoleReadAccess("moderator", true) // role: read only
note.acl = acl
note.saveInBackground { e ->
if (e != null) Log.w("ACL", "save failed: ${e.code}")
}
// The class gate above it is schema config, set in the dashboard:
// find/get requiresAuthentication, create authenticated, addField off CLP vs. ACL vs. master key: qual controle faz o quê
| Controle | Escopo | Configurado onde | Como falha |
|---|---|---|---|
| Permissão em nível de classe | Classe inteira, por operação | Schema (dashboard) | Deixada nos defaults permissivos |
| ACL | Um objeto | Em cada linha, no momento do save | Esquecida em objetos novos |
| Campos protegidos | Uma coluna | Schema | Colunas sensíveis legíveis por outros usuários |
| Master key | Ignora tudo acima | Só no ambiente do servidor | Embarcada num binário de cliente |
Os três primeiros se compõem numa escada de permissões que toda requisição sobe. O quarto é a saída de emergência da escada — indispensável no servidor, catastrófica em qualquer outro lugar. E os identificadores que os apps de fato carregam — o app ID e as chaves de API de cliente — pertencem a uma categoria mental completamente diferente: são extraíveis de qualquer binário, então identificam o app em vez de protegê-lo. Assuma que são públicos e deixe a camada de dados fazer o enforcement.
Onde uma requisição hostil morre
O diagrama também é o roteiro de auditoria: em cada gate, pergunte o que acontece quando um atacante com as suas chaves públicas chega como usuário anônimo, como usuário logado e como usuário de outro tenant. Todo “permitido” que te surpreender é o achado.
Como fazer hardening de um backend BaaS
| Passo | Ação | O que isso fecha |
|---|---|---|
| 1 | Configure as CLPs de toda classe: requiresAuthentication no mínimo, escritas restritas por papel | O clássico dump anônimo da tabela inteira |
| 2 | Desligue addField em todas as classes e a criação de classes pelo cliente | Deriva de schema e injeção de classes-lixo |
| 3 | ACL padrão em objetos do usuário: dono lê/escreve, público nada | Leituras e escritas entre usuários |
| 4 | Proteja colunas sensíveis (e-mail, tokens, scores) com regras por campo | Usuários lendo atributos privados de outros |
| 5 | Confine a master key a ambientes de servidor; rotacione por agenda e a cada vazamento | Exposição total por bypass |
| 6 | Direcione escritas sensíveis por funções de Cloud Code com classes trancadas atrás delas | Violação de regras de negócio e adulteração |
| 7 | Aplique rate limit em endpoints de auth e consultas caras | Credential stuffing e scraping em massa |
| 8 | Reteste de um cliente real com só as chaves públicas; logue e revise o uso da master key | Deriva de configuração passando despercebida |
Os passos 1–4 são enforcement na camada de dados — declarativo, verificado em todo caminho. Os passos 5–8 são disciplina operacional. As duas metades são necessárias; nenhuma é suficiente sozinha.
Disciplina de master key e o caminho privilegiado
A master key existe porque alguém legítimo — migrações, ferramentas de admin, jobs agendados — precisa poder ignorar os gates. Disciplina significa tratá-la como a credencial de root que ela é: injetada nos ambientes de servidor como configuração, nunca commitada, nunca logada, jamais embarcada em qualquer coisa que um usuário baixe, e usada por operação em vez de mantida como default de sessão. A rotação é a metade subestimada — chaves vazam silenciosamente para logs de CI e notebooks antigos, então rotacionar por agenda (e na hora, a qualquer suspeita) limita o raio de explosão de um vazamento que você nunca detectou.
O Cloud Code é o padrão que torna regras estritas na camada de dados vivíveis. Tranque uma classe por completo — zero escritas de cliente — e exponha uma função serverless como única porta. A função valida a entrada, aplica as regras de negócio que o schema não expressa (“só antes de o pedido ser despachado”), escreve com privilégio elevado e deixa trilha de auditoria. O gate da classe garante que o chokepoint não pode ser contornado; o chokepoint mantém a lógica revisável em um só lugar.
Casos de uso comuns
- O lockdown pré-lançamento. O checklist completo acima, rodado uma vez antes de os usuários reais chegarem — a hora de segurança de maior alavancagem que um time pequeno gasta.
- Isolamento de dados multi-tenant. ACLs restritas ao dono mais CLPs que exigem autenticação, para que o tenant A jamais consulte o tenant B — com enforcement abaixo do código da aplicação.
- Pagamentos e estoque. Classes trancadas com zero escritas de cliente, e funções de Cloud Code como caminho auditado para qualquer coisa que toque dinheiro ou inventário.
- Resposta a incidentes. Uma chave vazada ou uma surpresa nos logs dispara rotação, auditoria de acesso e nova rodada do teste de permissões de fora para dentro.
- Evidência de compliance. Uma matriz de permissões versionada e logs de uso da master key transformam “levamos segurança a sério” em artefato que um auditor consegue ler.
Você deveria endurecer na camada de dados ou no código da aplicação? Matriz de decisão
| Aplique na camada de dados (CLPs + ACLs) quando… | Aplique no código da aplicação (Cloud Code) quando… |
|---|---|
| A regra é sobre identidade e propriedade | A regra precisa de lógica de negócio ou estado entre objetos |
| Ela precisa valer em todo caminho, inclusive clientes futuros | Um único chokepoint auditado é o requisito |
| Um toggle no dashboard é a especificação inteira | Validação, enriquecimento ou efeitos colaterais pegam carona |
| Você quer segurança que sobreviva a reescritas do app | A regra muda mais rápido do que o schema deveria |
| O modo de falha do esquecimento é catastrófico | O modo de falha é um bug de negócio, não um vazamento |
Na prática a resposta é em camadas, não um ou outro: regras na camada de dados como o chão que sempre segura, funções na camada de aplicação para tudo que é condicional — a mesma requisição atravessa as duas.
Limitações e trade-offs
- Hardening é configuração, e configuração deriva. Classes novas chegam com defaults permissivos; sem o hábito de reauditar, o lockdown do ano passado se corrói em silêncio.
- Regras declarativas não expressam lógica. “Só os donos” é um toggle; “só reembolsável em 30 dias” é código — depender demais da camada de dados leva times a contorcer schemas em vez de escrever uma função.
- Rigor tem custo de experiência do desenvolvedor. Classes trancadas e schemas congelados atrasam a prototipação, e é por isso que a disciplina é faseada: aberto em desenvolvimento, trancado no lançamento.
- Rate limits e auditorias precisam de ajuste fino. Limites apertados demais estrangulam picos legítimos; logs que ninguém lê são decoração. Os dois precisam de dono, não só de um commit de setup.
- As camadas protegem dados, não tudo. Vulnerabilidades em dependências, senhas de usuário vazadas e engenharia social vivem fora deste modelo — endurecer a camada de dados é necessário, não suficiente, como o catálogo do OWASP API Security Top 10 deixa claro.
Hardening de segurança em BaaS no Back4app
O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. O checklist deste artigo mapeia no dashboard quase um para um: permissões em nível de classe e campos protegidos são checkboxes por classe, ACLs são aplicadas no servidor em toda requisição — pelos SDKs, REST e GraphQL — e a master key fica na configuração do servidor, onde o Cloud Code, o caminho privilegiado, pode usá-la por operação. As diretrizes de segurança percorrem a mesma passada passo a passo, de modo que endurecer um backend é uma tarde de toggles e um teste honesto de fora para dentro.
Perguntas frequentes
O que é hardening de segurança em BaaS?
É a passada pré-lançamento que converte um backend de desenvolvimento permissivo em um backend de produção trancado: permissões de classe restritas por operação, ACLs por objeto nos dados de usuário, master key confinada ao código do servidor, schema congelado, rate limits configurados e a configuração auditada a partir de um cliente real. Cada controle cobre uma camada diferente, e as camadas são verificadas em sequência a cada requisição.
O application ID é um segredo?
Não — trate-o como público. Client keys e app IDs viajam dentro de todo binário mobile e de toda página de JavaScript, onde qualquer um consegue extraí-los. Eles identificam o app; não autenticam quem chama. A proteção real vem do que o backend aplica depois da identificação: permissões em nível de classe, ACLs e autenticação — as camadas que seguram mesmo quando todas as chaves do cliente são conhecidas.
Por que a master key nunca pode ir embarcada num app cliente?
Porque ela ignora todos os gates: permissões de classe, ACLs, campos protegidos e verificações de autenticação são nulos para requisições com master key. Uma chave embarcada num binário pode ser extraída por qualquer pessoa que baixe o app, o que torna seu banco inteiro público para leitura e escrita. A master key pertence só ao código do servidor — usada por operação, jamais guardada onde um cliente alcança.
Qual a diferença entre CLPs e ACLs?
Escopo. A permissão em nível de classe é uma regra no schema que responde "quem pode executar esta operação nesta classe"; a ACL é dado em cada objeto respondendo "quem pode tocar nesta linha". A requisição passa primeiro pelo gate da classe, depois pelo gate do objeto, e qualquer um pode negar. O hardening usa os dois: traço largo no schema, grão fino nas linhas.
Como fazer a rotação de uma master key vazada?
Gere imediatamente uma chave nova no dashboard da plataforma, atualize todos os consumidores no servidor — Cloud Code, jobs, scripts de admin, CI — e revogue a chave antiga. Depois audite o que a chave vazada pode ter tocado enquanto era válida. A rotação também deve ser rotina, não só resposta a incidente: chaves envelhecem em logs, backups e notebooks antigos, então agende a rotação como se fosse renovação de certificado.
Quando as escritas devem passar por Cloud Code em vez do SDK?
Sempre que a regra exigir lógica, e não só identidade: invariantes entre vários objetos, precificação, estoque, qualquer coisa que envolva dinheiro ou cotas. O padrão endurecido tranca a classe para que clientes não escrevam direto e expõe uma função de Cloud Code como única porta — validação, enriquecimento e log de auditoria pegam carona, e o gate da classe garante que ninguém contorna o chokepoint.
Rate limits fazem parte de uma configuração de segurança em BaaS?
Sim — permissões decidem quem pode chamar um endpoint; rate limits decidem com que frequência. Sem eles, credenciais válidas viram ferramenta de scraping ou força bruta: endpoints de login sofrem credential stuffing e consultas abertas são colhidas na velocidade da linha. Aperte os limites em rotas de autenticação e consultas caras, e combine-os com alertas para que um pico anômalo vire aviso, não fatura surpresa.
Como auditar a configuração de segurança de um BaaS?
Teste de fora, como faria um atacante: só com as chaves públicas do cliente, tente ler e escrever em toda classe como usuário anônimo, como usuário autenticado e como usuário de outro tenant. Tudo que funcionar e não deveria é um achado. Repita após mudanças de schema, mantenha a matriz de permissões em documentação versionada e revise os logs em busca de usos de master key que não deveriam existir.