Autenticação de usuários em Banco de Dados – Savepoint
Autenticação de usuários em Banco de Dados
Este é um tema bastante polêmico, já tive algumas discussões acaloradas em listas de discussão (bom, o nome já diz que é para discutir, não é? 😉 ) onde até hoje muitos defendem uma opinião contraria a minha. Mas é um tema que me incomoda e estou longe de chegar a uma resposta conclusiva, portanto todos os comentários, pedras e sugestões são bem vindos.
Eu confesso que nos meus primeiros sistemas eu fiquei tentado a fazer isso:
Para cada usuário da aplicação, criar um usuário no banco de dados com o comando CREATE USER (ou com o comando CREATE ROLE).
Assim, a aplicação ficaria muito mais simples, eu não precisaria ficar me preocupando com criptografia de senhas e toda uma estrutura adicional que seria necessária se todos os usuários da aplicação se conectassem com o mesmo usuário no banco de dados.
A parte de auditoria também seria uma maravilha! Eu posso olhar qual usuário está conectado no Banco de Dados e guardar isso numa tabela de forma simples e confiável. Sempre saberei quem se conectou no banco de dados!
Logo percebi que meus dotes de desenvolvedor não são tão bons assim e passei a trabalhar mais de perto com bancos de dados. E aí fui percebendo os problemas deste tipo de sistema de autenticação de aplicações em bancos de dados. Não posso dizer que me tornei um conhecedor do assunto, mas sofri com diversas aplicações.
Me parece que as aplicações Cliente/Servidor tem um hábito grande de utilizar este tipo de esquema, embora eu já tenha visto isso em aplicações Web também. Já vi esquemas mais elaborados que tentam de uma forma ou outra contornar os problemas que eu vou citar a seguir, mas de qualquer forma, me parece que a decisão tomada no começo do desenvolvimento da aplicação sobre este assunto torna tudo mais complicado depois, embora eu já tenha (depois de muita briga) feito com que um fornecedor tenha alterado completamente o seu esquema de autenticação da aplicação.
1) Segurança contra conexão através de clientes diferentes da aplicação.
Imagine que o seu usuário utilize uma conexão através de ODBC ou JDBC a partir de uma suite de escritório que já deve estar instalada na máquina dele. Isto não leva mais do que 2 minutos e o banco de dados vira um livro aberto para o usuário!!!
É claro que você pode (e deve) restringir com GRANTs e REVOKEs o acesso a cada usuário e utilizar ROLEs para cada perfil. No entanto, veja, se você tem um GRANT como DELETE numa tabela, o usuário poderá apagar todos registros da tabela. Com um GRANT UPDATE o usuário pode alterar todos os dados. Seria melhor que o usuário só se conectasse pela aplicação, onde o desenvolvedor controla mais rigorosamente o acesso aos dados.
2) Quem cria os usuários e altera as suas senhas?
Com uma dúzia des usuários tudo corre bem. Com centenas de usuários, o trabalho do DBA começa a ficar sobrecarregado. Um agravante peculiar é o momento de colocar a senha do usuário. O DBA deverá estar presente ao lado do usuário, o que pode ser incômodo para eles. O usuário pode estar longe ou trabalhar em outro horário. Se isto acontecer, começaram a transmitir senhas por e-mail ou telefone, ou ainda pior… utilizar senhas padronizadas. Alguns podem achar isso um absurdo, mas eu já vi acontecer isso várias veses.
Você pode delegar o poder de criar usuários a aplicação, mas não conheço muitos DBAs que gostem da idéia de uma aplicação que pode criar usuários no banco por aí. Não é seguro e geralmente isso é feito concedendo superpoderes no banco de dados para a aplicação. Isto significa que o DBA perde totalmente o controle sobre o banco de dados. Veja bem, se existem funções distintas para o desenvolvedor e o DBA, é porque ambos devem ter atribuições distintas. Criar usuários no banco de dados ou alterar suas senhas, não deve ser nunca uma atribuição do desenvolvedor, pelo menos na base de produção. É só pensar no que vai acontecer no dia em que for descoberto um problema grave no banco de dados… de quem será a responsabilidade?
3) Quem apaga ou inativa os usuários?
Apesar de muito semelhante ao ítem anterior, há uma pequena diferença sobre quando isto ocorre. Usuários entram em férias, saem da empresa e quem é que lembra de avisar para desativar ou apagar o seu usuário? Quantas vezes não ligam para o DBA desesperados para trocar a senha de um usuário importante que saiu de férias e só ele tinha a senha para resolver um problema urgente? E os usuários que são demitidos, costumam não ficar muito felizes nesta época. Eles podem deixar a sua senha para um colega ou coisa pior. Veja que momento oportuno para boa fraude no sistema.
4) Administrar um banco de dados com muitos usuário é bem mais trabalhoso
Pode parecer uma besteira, mas lidar com um banco de dados com centenas de usuários criados, pode ser um verdadeiro pesadelo. Além de ter de criar os usuários e ficar alterando suas senhas com frequência, muita confusão pode acontecer quando você realiza rotinas mais delicadas com migração de dados. Se você acha que isto nunca ocorre, imagine algumas situações:
Migração para um novo servidor;
Migração de versão SGDB;
Migração da base de produção para a base de teste ou homologação.
Estas operações são sempre demoradas e propensas a erros. Quando muitos usuários existem criados no banco de dados, os erros se multiplicam. Erros em GRANTs, senhas que mudam, importação e exportação de objetos para cada usuário. É uma boa prática exportar e importar objetos por usuário e não todos num único arquivo, e com muitos usuários criados no banco isto pode se tornar bastante trabalhoso, ainda mais se a aplicação criar novos objetos para cada usuário (não estranhem não, eu também já vi isso e em larga escala)
5) Redundância de informação
Não demora muito para perceber que somente com GRANTs e REVOKEs não é possível controlar bem o acesso na aplicação. Você vai querer :
Controlar o acesso a telas específicas do sistema que envolvem várias tabelas diferentes.
Que o usuário tenha acesso a funções específicas na sua tela que não se enquadram nas especificadas pelos GRANTs e REVOKEs.
Que os usuários tenham acesso a apenas uma faixa de valores de uma tabela ou mais tabelas.
Todas estas situações exigem que você crie uma estrutura de tabelas para administrar estas permissões. Se você pensava em ter menos trabalho autenticando usuários direto no banco de dados, logo você vai perceber que é bem capaz de você ter mais trabalho ainda.
Tabelas de usuários, senhas e permissões por aplicação
Uma alternativa comum é criar logo algumas tabelas com os nomes de usuários e colunas para senha e telas e operações das quais o usuário poderá ter acesso. A estrutura poderá ser um pouco mais complexa, com o uso de grupos, tempo de validade de sessão, data de desativação automática de senha e outras funcionalidades interessantes que você pode e deve criar.
A aplicação se conectará ao banco de dados com um único usuário que terá todas as permissões necessárias para realizar as operações normais da aplicação. Isto significa que o usuário da aplicação não deve ser o OWNER dos objetos da aplicação e não deve ter GRANTs como DROP, CREATE, ALTER e TRUNCATE e situações normais.
Outro detalhe é que o usuário não deve ter acesso a senha da aplicação em momento algum, ao mesmo tempo que deva ser possível de trocar a senha periodicamente a partir de algum procedimento especial. No caso de aplicações que utiliza um servidor de aplicação, isto não apresenta nenhum problema. Já as aplicações cliente/servidor tradicionais terão que realizar operações um pouco mais criativas para lidar com isso, pois a senha deverá estar compilada junto com o código da aplicação.
Para contornar o problema da auditabilidade, você vai ter que utilizar um pouco mais de criatividade (muito menos do que você precisaria para resolver os problemas de segurança já citados). Você pode criar uma função no banco de dados e passar como parâmetro o nome do funcionário. Em alguns SGDBs a sua vida pode ser até mais simples, o ORACLE, por exemplo permitir a criação de TRRIGERs de sistema que são disparados quando um usuário se conecta. Além disso, você pode utilizar tabelas de histórico, logs do SGDB e outros recursos que variam um pouco conforme o fornecedor.
Autenticação externa via serviço de diretório
A maioria dos SGDBs possuem autenticação direta através de algum serviço de diretório como o AD ou LDAP. Isto permite uma autenticação centralizada para todas as suas aplicações com a mesma senha para todos os usuários. É sem dúvida uma solução ótima em termos de senhas, mas não elimina a necessidade de se criar os usuários no banco de dados.
É possível, com um pouco de trabalho adicional, implementar a sincronização a criação de usuários no diretório com a criação de usuários no banco de dados, mas pode ser algo um pouco menos trivial. De qualquer forma, todos os usuários nomeados da aplicação deverão existir no serviço de diretório. Isto significa também que o seu administrador de sistema será responsável por todas as senhas dos usuários.
Os usuários ficarão muito felizes em utilizar a mesma senha para várias operações diferentes. Algumas pessoas podem considerar isto um tanto estranho. Mas imagine que se você tiver um bom administrador de sistemas e um bom serviço de diretórios, você poderá ter muito mais controle sobre as senhas do que em outras situações.
Não confunda isso com a autenticação via sistema operacional (IDENT) que checa apenas se o nome do usuário do SO remoto é igual ao nome do usuário criado no banco de dados. A autenticação via IDENT é muito insegura pois permique que qualquer pessoa que consiga conectar um computador na rede (mesmo sem se autenticar no serviço de diretório) com um usuário no seu SO igual ao nome de um usuário da aplicação se autentique. Imagine por exemplo que você crie no seu computador um usuário com o nome 'ADMIN' e este seja o nome do usuário que administra a aplicação.
Eu realmente tenho uma solução milagrosa para todos os problemas citados. Sei que sempre existirão usuários especiais que poderão consultar dados diretamente no banco de dados. Para estes poucos casos (se não forem poucos, então deve haver algumas funcionalidades faltando na aplicação) basta criar algumas VIEWS e dar acesso limitado apenas a estes objetos para as suas contas criadas no banco de dados. Nada além disso.
Já vi esquemas mirabolantes para contornar os problemas citados nos itens 1, 2 e 3, mas nunca vi alguém contornar o ítem 4. Muito pelo contrário, quanto mais tentam contornar o problema da segurança, mais complicam a vida do DBA.
Acredito que a criação de alguns frameworks para autenticação possam ser soluções robustas, mas será difícil convencer diferentes fornecedores a adotarem uma mesma solução a curto prazo. É nestes momentos em que ficar refém de fonecedores de pacotes nos lembram da beleza do Software Livre!
Podem existir formas completamente diferentes de autenticação que não incorram em tantos problemas de segurança e administração. Como eu disse no começo, não sou um expert no assunto. Quero conhecer novas soluções. Mas até agora, a maioria delas parece se basear nos 3 tipos citados:
1) Criação de usuários normais direto no banco de dados.
2) Criação de usuário único da aplicação
3) Autenticação de usuários utilizando um serviço de diretório
Se você conhecer outras soluções ou discorda dos meus argumentos, por favor, me conte para eu melhorar este artigo e sugerir novas soluções para os desenvolvedores da aplicações que "sobrevivem" nos bancos de dados que eu administro!
Previous Post12 Dicas para o desenvolvedor lidar com o DBA
Next PostInterview With Bruce Momjian
2007-06-21 às 20:27
Depois de ler este artigo, levando em consideração que eu manjo tando de SGDB quanto de física sub atômica, só tenho uma consideração a fazer:
Jogue a tarefa de cuidar dos usuários para o SysAdmin. Ou seja, todos os meus exércitos no Serviço de Diretórios.
2007-06-22 às 10:48
"Eu realmente tenho uma solução milagrosa para todos os problemas citados", qual é?
Sempre usei a opção:
E acho que é a melhor pois com os recursos adicionais que os SGBDs trazem, em especial o Oracle, facilita bastante.
2007-06-22 às 10:51
Esqueci de agradecer! São pontos que não podemos esquecer e que são difíceis de se negociar.
2007-07-26 às 11:24
A única opção sã em termos de segurança é a 3. Aliás, vide SE PostgreSQL.
2007-10-07 às 11:50
[…] sujeitas a alterações a qualquer momento. Um bom exemplo disto foi quando eu escrevi sobre "Autenticação de Usuários em Bancos de Dados". Eu me arrisquei um pouco mais e divulguei este texto na lista do Oracle-BR. O Chiappa, que […]
SAVEPOINT » Segurança no PostgreSQL - Parte I: "A Saga" disse:
2008-05-30 às 17:39
[…] a parte de segurança no Oracle e andei investigando algumas questões sobre o assunto aqui e acolá neste blog e na palestra sobre melhores práticas que fiz no FISL 9.0 e no PGCon Brasil 2007. […]
Helio Geminiano disse:
2010-03-19 às 10:56
Apesar de ser um post antigo, resolvi apresentar a minha opinião. Ela é resultado de mais de 15 anos trabalhando do bancos Oracle.
1. A opção de conceder privilégios através de roles, que podem ser ajustadas como default ou não, resolvem o primeiro item. Um role apenas para conexão e leitura (default, sem senha) permite o usuário se conectar, fazer SELECTs e mais nada. Uma segunda role (não default, com senha desconhecida pelo usuário) permite update, insert e delete apenas através dos aplicativos.
2 e 3. Um usuário com privilégios para criar, bloquer e eliminar usuários (e não "concedendo superpoderes") resolve os itens 2 e 3. Uma tela simples no aplicativo auxiliar esse gestor de usuários (que não irá dar comando como CRETE USER direto no banco).
4. Ninguém migra banco executando comandos "um a um". Fazemos um script que lê o banco "origem", gerando os comandos que serão executados no banco "destino". Por exemplo (simplificadíssimo):
SELECT ' CREATE USER ' || USERNAME || ' IDENTIFIED BY VALUES "' || PASSWORD || "';'
Se existem 10 ou 10.000 usuários, o trabalho de elaborar o script é mesmo. A margem de erro também.
O mesmo se dá para privilégios, roles, etc.
5. Através do banco não controlarei acessos a telas, mas acessos a atividades. Se bloquear um DELETE em uma tabela, por exemplo, ele pode acessar a vontade a tela que permite excluir dados de tal tabela. Mas excluir mesmo, ele não vai. Quanto ao limite por faixas de valores, realmente o Oracle não permite essa funcionalidade. Mas diversos experts em AD me disserem que ele também não permite. Associar um usuário a um grupo e verificar, no aplicativo, se o mesmo pertence a este grupo (e assim limitar por faixas) não seria uma funcionalidade do AD, mas do aplicativo. Posso fazer o mesmo com o Oracle, associando o usuário a roles e testando no aplicativo.
O que mais encontro é desconhecimento das possibilidades do banco Oracle. Como segurança é cada vez mais um requisito das empresas, fico a vontade com tais capacidade do banco. Com FGA posso auditar com tranquilidade tudo o que me interessa e indicar os possíveis "culpados".
a) Criar usuários distintos para atuar como "dono" dos objetos de cada sistema. Esses usuários serão raramente utilizados para conexão com o banco.
b) Criar usuários para acesso de trabalho no banco. Prefiro 1×1 (um usuário no banco para cada "pessoa física").
c) Não crie sinônimos públicos para que os usuários do item "b" acessem os dados dos usuários do item "a". Utilize a sintaxe dono.tabela (ou como aparece nos manuais da Oracle, schema.table). Ou estude o comando ALTER SESSION SET CURRENT_SCHEMA.
Para terminar: essa é apenas minha opinião. Em vários anos atuando como DBA, não vi ainda solução melhor. Quando encontrar, adotarei de bom grado.
2010-05-06 às 15:39
Helio Geminiano, sou obrigado a reconhecer que não penso mais da mesma forma que eu pensava quando escrevi este post. Apesar de concordar com você em 95% do que você escreveu eu gostaria de fazer algumas observações:
* Não são todos que utilizam Oracle e não são todos que utilizam a versão enterprise do Oracle. Então não são todos que tem acesso ao FGA. O PostgreSQL tem o SE PostgreSQL que é uma alternativa bem interessante.
* Hoje acredito que cada método de autenticação tem a sua aplicação em um contexto diferente;
Tanto que este assunto me preocupou que eu mudei de idéia e fiz esta palestra: http://www.slideshare.net/telles/postgresql-o-elefante-encouraado-presentation