Usuários e Permissões
Num banco grande, muita gente usa o mesmo banco: o caixa só precisa ler os preços, o gerente pode mudar os salários, o estagiário nem deveria ver a folha de pagamento. Para isso, os bancos com servidor (MySQL, PostgreSQL, SQL Server) têm usuários e permissões: cada pessoa entra com um login e só pode fazer o que foi liberado para ela. O SQLite, que é um banco embutido num arquivo, não tem nada disso — e nesta aula você vai entender por quê, ver os comandos GRANT e REVOKE dos bancos com servidor e descobrir o que o SQLite oferece no lugar.
- Por que o SQLite não tem usuários nem senhas (a resposta está no "embutido num arquivo").
- Como os bancos com servidor criam usuários (
CREATE USER) e dão poderes (GRANT). - Como tirar um poder de volta (
REVOKE). - O princípio do menor privilégio, e por que ele protege até contra o SQL Injection.
- O que faz as vezes de permissão no SQLite: a permissão do arquivo (no sistema), a conexão só-leitura e a view que mostra só algumas colunas.
Os comandos CREATE USER, GRANT e REVOKE são ilustrativos: eles não existem no SQLite, então não rodam no editor. Vêm da documentação oficial de cada banco. Os exemplos do que o SQLite faz no lugar rodam de verdade, no editor.
A ideia: a loja com chaves diferentes
Pense na Loja Aurora à noite, fechada. Nem todo funcionário tem a mesma chave:
- o caixa tem a chave da frente, mas não a do cofre;
- a gerente tem a chave do cofre e do escritório;
- o estoquista só entra no depósito.
Cada chave abre só o que aquela pessoa precisa. Se o chaveiro do caixa for roubado, o ladrão não chega ao cofre. Num banco com servidor, as "chaves" são as permissões, e cada usuário recebe só as suas. Dar a cada um só o necessário é o princípio do menor privilégio — a regra de ouro desta aula.
1. Por que o SQLite não tem usuários
O SQLite é um banco embutido: o banco inteiro é um arquivo (o loja.db) e o "servidor" é a própria biblioteca que roda dentro do seu programa. Não há um servidor ligado o tempo todo, esperando gente se conectar com login e senha. Quem pode abrir o arquivo pode fazer tudo nele; quem não pode abrir, não faz nada.
Por isso, no SQLite, quem manda é o sistema operacional, não o banco. A permissão de ler e escrever é a permissão do arquivo loja.db (dona Ana, no computador dela). No Linux, você a vê e a muda com as ferramentas do sistema:
$ ls -l loja.db -rw-r--r-- 1 ana ana 45056 out 18 11:14 loja.db « a Ana lê e escreve; os outros só leem
Como o SQLite nasceu para ficar dentro de um programa (um aplicativo de celular, um navegador, um joguinho), um sistema de usuários dentro dele não faria sentido: o controle de quem usa o aplicativo é do próprio aplicativo e do sistema.
A aula Os Bancos Famosos explica a diferença. Em resumo: o SQLite é um arquivo que o seu programa abre (sem servidor, sem login). O MySQL, o PostgreSQL e o SQL Server são servidores: ficam ligados numa máquina, e os programas se conectam a eles por rede, cada um com um usuário e uma senha. Usuários e permissões só existem nesse segundo grupo.
2. Criar um usuário (bancos com servidor)
Nos bancos com servidor, primeiro você cria o usuário e depois dá as permissões. No MySQL, segundo a documentação oficial, é assim:
CREATE USER 'caixa'@'localhost' IDENTIFIED BY 'uma_senha_forte';
- CREATE USER
- "Criar usuário". Cria a conta, ainda sem nenhum poder sobre os dados.
- 'caixa'@'localhost'
- No MySQL, o usuário é o nome mais de onde ele se conecta (
localhost= a própria máquina). - IDENTIFIED BY '…'
- Define a senha. Sem permissões, esse usuário entra mas não vê nada ainda.
No PostgreSQL o comando equivalente é CREATE ROLE caixa LOGIN PASSWORD '…'; e no SQL Server costuma-se criar um login no servidor e depois um usuário no banco (CREATE LOGIN … e CREATE USER …). Os nomes mudam; a ideia é a mesma: a conta nasce vazia.
3. Dar poderes: GRANT
GRANT ("conceder") é o comando que entrega uma permissão a um usuário. A forma geral é sempre a mesma: que poder, sobre o quê, para quem.
GRANT que-poderes ON qual-tabela TO qual-usuário;
Para o nosso caixa, que só precisa ler produtos e clientes, damos só o SELECT. Veja a forma em cada banco, como aparece na documentação oficial:
GRANT SELECT, INSERT ON aurora.produtos TO 'caixa'@'localhost';
GRANT SELECT ON produtos TO caixa;
GRANT SELECT ON OBJECT::dbo.produtos TO caixa;
Depois disso, o caixa consegue SELECT na tabela produtos, mas um DELETE dele é recusado pelo banco, porque esse poder não foi concedido. Os poderes mais comuns são os próprios comandos que você já conhece: SELECT, INSERT, UPDATE, DELETE.
Só algumas colunas
Dá para ser ainda mais fino e liberar só certas colunas. No PostgreSQL, a documentação mostra o GRANT por coluna assim:
GRANT SELECT (nome, cargo) ON funcionarios TO caixa;
Agora o caixa vê nome e cargo dos funcionários, mas não o salario. Guarde essa ideia: no fim da aula você vai fazer algo parecido no SQLite, com uma view.
4. Tirar poderes de volta: REVOKE
REVOKE ("revogar") é o contrário do GRANT: tira uma permissão. A forma é igual, só trocando o TO ("para") por FROM ("de"):
REVOKE INSERT ON aurora.produtos FROM 'caixa'@'localhost';
REVOKE SELECT ON produtos FROM caixa;
Depois do REVOKE INSERT, o caixa continua lendo (ainda tem o SELECT), mas não insere mais. É assim que se corrige um poder dado a mais.
| Comando | O que faz | Palavra-chave de ligação |
|---|---|---|
CREATE USER | Cria a conta (sem poderes) | — |
GRANT | Dá uma permissão | TO (para) |
REVOKE | Tira uma permissão | FROM (de) |
5. O princípio do menor privilégio
A regra é simples: dê a cada usuário só o que ele precisa, e nada mais. O site que só mostra o catálogo deve conectar com um usuário que só tem SELECT. Assim, mesmo que esse site tenha uma falha de SQL Injection, o estrago é limitado: o invasor não consegue um DELETE ou um DROP TABLE, porque o usuário daquele site nunca teve esse poder.
O menor privilégio é uma segunda linha de defesa, não a primeira. A primeira continua sendo usar parâmetros para que o dado do visitante nunca vire SQL. As duas juntas: parâmetros para o ataque não acontecer, e poucas permissões para, se algo escapar, o dano ser pequeno.
6. O que o SQLite faz no lugar
Sem usuários, o SQLite resolve "quem pode o quê" por outros caminhos. Dois deles você roda aqui no editor.
Conexão só-leitura
Você pode abrir o banco em modo só-leitura, e aí nenhuma escrita passa. No editor, o PRAGMA query_only = ON liga esse modo. Um SELECT continua funcionando:
PRAGMA query_only = ON; SELECT nome, salario FROM funcionarios WHERE id = 1;
Mas uma tentativa de mudar os dados é barrada, com a mensagem real do SQLite:
PRAGMA query_only = ON; UPDATE funcionarios SET salario = 99999 WHERE id = 1;
A mensagem attempt to write a readonly database ("tentativa de escrever num banco só-leitura") é o SQLite dizendo "aqui você só lê". Um programa que só mostra dados deve abrir o banco assim — é o SELECT-only do mundo SQLite.
Uma view para mostrar só algumas colunas
Lembra do GRANT SELECT (nome, cargo), que escondia o salário? No SQLite, o mais perto disso é uma view (aula Views): uma "tabela de mentira" que mostra só as colunas que você escolher. Você cria a view com as colunas públicas e deixa o programa usar a view, não a tabela:
CREATE VIEW equipe AS SELECT nome, cargo FROM funcionarios; SELECT * FROM equipe;
A view equipe mostra nome e cargo dos oito funcionários, e nada do salário. Quem usa a view não tem como pedir a coluna escondida: ela não existe ali. Veja o que acontece ao tentar:
CREATE VIEW equipe AS SELECT nome, cargo FROM funcionarios; SELECT salario FROM equipe;
O erro no such column: salario ("não existe a coluna salario") confirma: pela view, o salário está fora de alcance. É um controle por dentro do banco, que funciona mesmo no SQLite. (Não é uma tranca de verdade — quem tem o arquivo ainda alcança a tabela original —, mas organiza bem o acesso dentro do programa.)
Lá, o costume é criar a view com as colunas públicas e dar GRANT SELECT só na view, revogando o acesso à tabela crua. Aí a view deixa de ser só organização e vira uma tranca de verdade. No SQLite, falta a parte do GRANT; sobra a view como boa prática de organização.
Quando dá errado
GRANT no SQLite
Como o GRANT não existe no SQLite, escrevê-lo no editor dá erro de sintaxe — o motor não conhece a palavra:
GRANT SELECT ON produtos TO caixa;
A mensagem near "GRANT": syntax error ("erro de sintaxe perto de GRANT") é o SQLite dizendo que não entende o comando. Isso é esperado: esses comandos são só dos bancos com servidor.
Referência rápida
| Onde | Controle de acesso |
|---|---|
| MySQL / PostgreSQL / SQL Server | CREATE USER, GRANT, REVOKE (usuários e permissões por tabela e por coluna) |
| SQLite — no sistema | Permissão do arquivo loja.db (quem pode abrir) |
| SQLite — na conexão | Abrir só-leitura (PRAGMA query_only = ON no editor) |
| SQLite — no banco | VIEW mostrando só algumas colunas |
Exercícios
1. Por que o SQLite não tem usuários nem senhas?
2. Qual comando dá a um usuário o poder de ler uma tabela, num banco com servidor?
3. O site só mostra o catálogo. Pelo princípio do menor privilégio, com que usuário ele deve conectar?
4. Tirar um poder
Complete o comando que tira do usuário caixa o poder de inserir na tabela produtos (MySQL). Lembre a palavra que liga o comando ao usuário:
Experimente: a view que esconde o salário
Missão: crie uma view chamada equipe que mostre só nome e cargo dos funcionários (sem o salário) e, depois, liste a view inteira. Devem vir 8 linhas, com as colunas nome e cargo.
-- 1. crie a view equipe só com nome e cargo -- 2. SELECT * nela SELECT * FROM funcionarios;
CREATE VIEW equipe AS SELECT nome, cargo FROM funcionarios; SELECT * FROM equipe;
Missão final: trancar a escrita
Missão: ligue o modo só-leitura e tente, de propósito, dar um aumento ao funcionário de id 1. A caixa espera o erro de banco só-leitura. (Dica: PRAGMA query_only = ON; antes do UPDATE.)
UPDATE funcionarios SET salario = 99999 WHERE id = 1;
PRAGMA query_only = ON; UPDATE funcionarios SET salario = 99999 WHERE id = 1;
Resumo
- Bancos com servidor (MySQL, PostgreSQL, SQL Server) têm usuários e permissões:
CREATE USERcria a conta,GRANTdá poderes (comTO),REVOKEtira (comFROM), até por coluna. - O SQLite é um banco embutido num arquivo: não tem usuários. Quem pode abrir o arquivo faz tudo; o controle fica com o sistema operacional.
- No lugar das permissões, o SQLite oferece: a permissão do arquivo, a conexão só-leitura (
PRAGMA query_only = ONdáattempt to write a readonly databasenuma escrita) e a view que mostra só algumas colunas. - Em qualquer banco, vale o menor privilégio: dê só o necessário. É a defesa que limita o estrago se um ataque passar — mas a defesa principal continua sendo o parâmetro.