Pular para o conteúdo

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.

dataforge
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:

dataforge
// 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).

bash
dataforge install --limpar-cache   # se suspeitar do cache local

Conflito 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:

dataforge
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").
  • .env e forge.local.toml no .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:

dataforge
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 2

Autorização#

Autenticação diz quem é; autorização diz o que pode. A segunda é regra de negócio, e nenhuma biblioteca a escreve por você:

dataforge
// 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.server do Python, que não foi feito para exposição direta.
  • Rode como usuário sem privilégio. O Dockerfile do 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ódigoSobre
DF0507pacote corrompido — o sha256 não bate
DF0508pacote com caminho inseguro (../ ou link simbólico)
DF1203credenciais recusadas
DF1304falha de TLS
DF1308sessão inválida ou expirada
DF1311origem não permitida (CORS)
DF1312limite de requisições
DF1505dado fora do esquema

dataforge explain DF0508 explica cada um.