Modelo de Segurança
Modelo de Segurança
O desenho de segurança do Chinaski é simples de descrever: verificar tudo o que é informado ao servidor, assinar tudo o que o navegador carrega e retardar qualquer pessoa que se comporte mal. Esta página explica as quatro peças em que isso se apoia: integridade de subrecursos, a content security policy, confiança de IP de cliente e rate limits/bloqueios.
Integridade de Subrecursos (SRI)
Os scripts e stylesheets auto-hospedados da interface de administração (o próprio CSS da UI de admin, fontes, o editor e os scripts de configurações) carregam hashes de integridade calculados. Quando o navegador carrega um desses arquivos, ele o verifica contra o hash publicado na página: um script adulterado ou trocado é recusado antes de poder executar.
Detalhes práticos:
- Os hashes são calculados quando o aplicativo inicia. Se você atualizar esses arquivos de recurso em disco, reinicie o aplicativo para que hashes novos sejam publicados.
- Se um arquivo de recurso estava ilegível na inicialização, a página carrega esse arquivo sem o atributo de integridade (com um aviso no log) em vez de quebrar a página.
Content Security Policy (CSP)
Toda resposta carrega uma Content Security Policy estrita:
- O conteúdo da página é restrito por padrão à origem do próprio site; scripts e estilos inline só executam se o servidor os marcou com um nonce gerado na hora para aquela requisição.
- Os envios de formulário são restritos ao seu próprio servidor; o enquadramento (framing) por outros sites é bloqueado.
- A integração de analytics/verificação de bots (Cloudflare Turnstile) é o único ponto de contato externo permitido, e desaparece por completo no modo airgap.
- Junto com a CSP, as respostas também carregam proteção contra framing, proteção contra sniffing de content-type, uma referrer policy estrita, HSTS de um ano (espera-se que o TLS termine no seu reverse proxy) e uma Permissions-Policy que desabilita recursos do navegador que o CMS nunca usa (câmera, microfone, geolocalização, pagamento, USB e mais).
Duas exceções deliberadas, ambas seguras e intencionais: as pré-visualizações de conteúdo relaxam a política porque renderizam o HTML do seu tema real (essas URLs exigem uma sessão de admin ou um token secreto de pré-visualização), e as páginas públicas de formulário são intencionalmente incorporáveis por outros sites; os envios delas ainda vão apenas para o seu servidor.
Confiança de IP de cliente (X-Forwarded-For)
Rate limits, bloqueios de login e logs precisam todos do endereço IP real do visitante. O CMS o decide assim:
- Se a conexão chega de um proxy confiável (por padrão, apenas loopback, a configuração padrão em que um proxy Caddy ou nginx fica de frente para a internet), o CMS lê os headers encaminhados e confia neles.
- Se a conexão chega de qualquer outro lugar, os headers encaminhados são ignorados por completo e o endereço real da conexão é usado; é por isso que ligar o servidor a uma interface pública permitiria que qualquer pessoa derrotasse seus rate limits.
- Um proxy em uma rede que não seja loopback (por exemplo, uma bridge do Docker) precisa ser adicionado por meio da configuração
CHINASKI_TRUSTED_PROXIES(endereços IP ou faixas IPv4 separados por vírgula) para que os headers encaminhados sejam respeitados. Os exemplos de proxy fornecidos usam loopback e não precisam de configuração.
Rate limits e bloqueios
O Chinaski aplica rate limit, por endereço IP, às superfícies com maior probabilidade de abuso:
| Superfície | Limite |
|---|---|
| Login de admin | Os bloqueios escalam: 1 minuto após 5 tentativas falhas, 5 minutos após 10, 30 minutos após 20. Pare de tentar por cerca de 10 minutos e a contagem é zerada. |
| Autorregistro | 5 tentativas do mesmo IP em sucessão rápida disparam um bloqueio de 1 hora (e o próprio registro precisa antes estar habilitado nas configurações) |
| Recuperação de senha | 5 requisições do mesmo IP disparam um bloqueio de 1 hora |
| Envios de formulários públicos | No máximo 5 por hora por formulário e 30 por hora entre todos os formulários, por IP; além disso você recebe HTTP 429 “Too many submissions” |
| API REST | Cada chave de API é limitada por minuto (padrão de 100 requisições), contadas atomicamente entre todos os workers do servidor; requisições em excesso recebem HTTP 429 com um header Retry-After informando quando tentar de novo |
| URLs suspeitas | Sondagens conhecidas de scanners (.env, .git/config, wp-login.php, wp-admin, phpmyadmin e afins) são registradas com todos os detalhes da requisição e respondidas com um 404 seco que não revela nada |
Alguns detalhes que vale conhecer:
- A atividade elevada de falhas de login é gravada no log de eventos, de modo que ataques repetidos sejam notados mesmo quando ninguém está acompanhando os logs ao vivo.
- O rate limiting de formulários usa como chave o IP real do cliente, então continua preciso mesmo quando o CMS omite os IPs dos visitantes por razões de privacidade (sinais Do Not Track / Global Privacy Control, ou uma configuração de armazenamento de IP por formulário).
- Em vez de rejeitar de imediato, caminhos abusivos podem sofrer tarpitting: a resposta é deliberadamente atrasada por alguns segundos. Isso não bloqueia: visitantes legítimos não são afetados, enquanto ataques automatizados perdem tempo.
O que tudo isso soma
- O tráfego de entrada é autenticado por chaves de sessão que o seu servidor assina, nunca apenas por valores fornecidos pelo navegador.
- Tudo o que o navegador do admin carrega é verificado por hash (SRI) e checado por política (CSP).
- Os limites de confiança são explícitos: o daemon sabe em quais redes pode acreditar e recusa headers encaminhados de qualquer outra.
- O abuso dispara limitação, atraso ou bloqueios, em vez de erros que vazam informações úteis.
- Toda tentativa falha e toda sondagem é registrada, de modo que os incidentes sejam visíveis depois do fato: no log de auditoria, no log de eventos e nos dashboards de admin.