Segurança
O que a linguagem garante por construção, e o que continua sendo sua responsabilidade.
Segurança não se acrescenta depois. Esta página lista o que o DataForge garante por construção — coisas que você não consegue errar mesmo querendo — e o que ele não pode garantir por você.
Injeção de SQL#
Garantido. O construtor de consultas não tem como pôr um valor no texto da consulta: valores viram parâmetros, sempre.
adopt Forge
db := Forge.conectar(":memory:")
Forge.executar(db, "create table u (id integer primary key, nome text)")
malicioso := "'; drop table u; --"
Forge.de(db, "u").inserir({"nome": malicioso})
// a tabela continua lá — o valor foi tratado como dado
assert "u" in Forge.tabelas(db)A lista de operadores também é fechada: .onde("x", operador, v) só aceita os operadores conhecidos. Um operador vindo de variável seria outro caminho de injeção.
XSS nos templates#
Garantido por padrão. O Kiln escapa toda interpolação de template:
// render "pagina.html" with {"nome": entrada_do_usuario}
//
// No template: <p>{{ nome }}</p>
// Se 'nome' for '<script>alert(1)</script>', sai escapado — o
// navegador mostra o texto, não executa.Escapar é o padrão, não uma opção a lembrar. Ver Kiln: páginas.
Travessia de caminho em pacotes#
Garantido. A extração de um pacote recusa qualquer entrada com ../ ou link simbólico — um pacote não pode escrever fora da própria pasta.
O tarball também é reprodutível (mtime zerado, uid/gid zerados): sem isso o sha256 mudaria a cada empacotamento, e a verificação de integridade não significaria nada.
Integridade dos pacotes#
Garantido. Todo pacote instalado tem o sha256 registrado no forge.lock. Se o conteúdo mudar entre o registro e você, a instalação falha com IntegrityError (DF0507).
dataforge install --limpar-cache # se suspeitar do cache localConflito de versão#
É erro, não aviso. Se dois pacotes pedem faixas incompatíveis do mesmo terceiro, o resolvedor falha dizendo quem pediu o quê. Instalar duas cópias em versões diferentes gera bug irreproduzível.
TLS#
Verificado por padrão. Http.get e as conexões de banco verificam o certificado. Desligar exige dizer isso explicitamente — e a documentação não ensina como, de propósito.
Senhas no editor#
A extensão do VS Code guarda senhas de banco no cofre do sistema (SecretStorage), não no settings.json — que muita gente versiona sem perceber. A URL salva leva um marcador no lugar da senha.
O que continua sendo sua responsabilidade#
Segredos#
A linguagem não tem como saber que um texto é uma senha. As regras valem aqui como em qualquer lugar:
adopt Forge
// certo: vem do ambiente
db := Forge.conectar(ambiente("DATABASE_URL") ?? ":memory:")
// errado: vai para o repositório junto com o código
// db := Forge.conectar("postgres://usuario:senha123@prod/app")- Nunca escreva credencial no código — use
ambiente("NOME"). .enveforge.local.tomlno.gitignore.- Se um segredo vazou para o histórico do git, rotacione: apagar o commit não basta, ele já foi clonado.
Validar o que vem de fora#
O corpo, a query e os cabeçalhos de uma requisição vêm do cliente. Trate-os como hostis:
adopt Forge
db := Forge.conectar(":memory:")
Usuario := Forge.modelo("Usuario", {
"id": {"tipo": "Serial"},
"email": {"tipo": "Texto", "obrigatorio": yes, "validacoes": ["email"]},
"idade": {"tipo": "Inteiro", "validacoes": [["minimo", 0], ["maximo", 130]]}
}, {"conexao": db})
Forge.migrar_tudo(db)
monitor:
Usuario.criar({"email": "não-é-email", "idade": -5})
handle ValidationError as e:
assert len(e.campos) is 2Autorização#
Autenticação diz quem é; autorização diz o que pode. A segunda é regra de negócio, e nenhuma biblioteca a escreve por você:
// route DELETE "/pedidos/:id":
// given req.sessao["usuario"] is void:
// respond 401, {"erro": "não autenticado"}
//
// pedido := buscar(params.id)
// given pedido["usuario_id"] isnt req.sessao["usuario"]:
// respond 403, {"erro": "não é seu"}
//
// remover(params.id)
// respond 204, ""O erro clássico é conferir só a autenticação — e qualquer usuário logado apagar o pedido de qualquer outro.
Limite de requisições#
O Kiln tem rate_limit, mas quem decide o limite é você. Sem ele, uma rota de login é um convite a força bruta.
Produção#
- Ponha um nginx ou Caddy na frente do Kiln. Ele roda sobre o
http.serverdo Python, que não foi feito para exposição direta. - Rode como usuário sem privilégio. O
Dockerfiledo projeto já faz isso. - `dataforge check --strict` no CI. O analisador acha erro de nome e de aridade antes do usuário achar.
Relatar uma vulnerabilidade#
Se você encontrou algo que permite executar código, ler arquivo fora do escopo, ou contornar as garantias desta página:
- Não abra issue pública. Ela é indexada em minutos.
- Escreva para o e-mail do mantenedor no repositório, com o que você fez e o que aconteceu.
- Um exemplo mínimo que reproduz vale mais que uma descrição longa.
Os erros que ajudam#
| Código | Sobre |
|---|---|
DF0507 | pacote corrompido — o sha256 não bate |
DF0508 | pacote com caminho inseguro (../ ou link simbólico) |
DF1203 | credenciais recusadas |
DF1304 | falha de TLS |
DF1308 | sessão inválida ou expirada |
DF1311 | origem não permitida (CORS) |
DF1312 | limite de requisições |
DF1505 | dado fora do esquema |
dataforge explain DF0508 explica cada um.