Primeiro alguns antecedentes.
O projeto LedgerSMB é um projeto de software de contabilidade financeira de código aberto executado no PostgreSQL. Implementamos uma quantidade muito grande de lógica de negócios em funções definidas pelo usuário, que atuam como a principal ferramenta de mapeamento entre os métodos de objeto do programa e o comportamento do banco de dados. Atualmente, usamos usuários de banco de dados como usuários de autenticação, em parte por opção (isso permite uma lógica de segurança centralizada, para que outras ferramentas possam ser escritas e reutilizar as permissões dadas aos usuários) e em parte por necessidade (depois que bifurcamos do SQL-Ledger, há não havia muitas opções para atualizar a segurança nessa base de código).
Isso nos dá acesso a um número razoável de opções de conexão única às quais o PostgreSQL tem acesso, do LDAP ao Kerberos 5. Podemos até usar o PAM no que diz respeito às senhas. Também nos permite reutilizar permissões ao integrar com outros aplicativos ou permitir outras interfaces de cliente. Para um aplicativo de contabilidade financeira, isso parece uma vitória líquida.
Há custos óbvios envolvidos. Para o aplicativo da web, estamos muito limitados aos tipos de autenticação http que podem ser suportados. DIGEST, por exemplo, está totalmente fora. O BASIC funciona e poderíamos implementar o KRB5 com bastante facilidade (pretendo ter isso suportado e funcionando imediatamente para 1.4). Medidas de autenticação muito fortes não podem ser gerenciadas adequadamente diretamente, embora provavelmente possamos corrigi-las, se necessário (por exemplo, BASIC + certificado SSL do lado do cliente com um cn correspondente ao nome do usuário e uma raiz específica ca).
Ao mesmo tempo, recebemos muitas críticas, principalmente do pessoal do desenvolvimento e, mais ocasionalmente, de dba's que me dizem que o aplicativo deve ser a barreira de segurança, não o banco de dados. Minha opinião ainda é que um perímetro de segurança menor geralmente é melhor, que a reutilização da lógica de negócios e da lógica de segurança andam juntas e que me parece perigoso reutilizar a lógica de negócios sem reutilizar a lógica de segurança no mesmo nível do programa.
Estou perdendo alguma compensação importante aqui? Existem pegadinhas que não estou considerando?
Acho que você está confundindo autenticação e autorização .
Concordo plenamente que é sensato manter o modelo de segurança no banco de dados, especialmente porque o LedgerSMB foi projetado tendo em mente o acesso de vários clientes. A menos que você planeje usar 3 camadas com uma camada de middleware, faz todo o sentido ter usuários como funções de banco de dados, especialmente para algo como um aplicativo de contabilidade.
Isso não significa que você precisa autenticar os usuários no banco de dados usando um método de autenticação suportado pelo PostgreSQL. Seus usuários de banco de dados, funções e concessões podem ser usados para autorização somente se você quiser.
Veja como funciona para uma interface do usuário da web, por exemplo:
jane
conecta-se ao servidor web ui e autentica usando qualquer método desejado, por exemplo, handshake de certificado de cliente HTTPS X.509 e autenticação DIGEST. O servidor agora tem uma conexão de um usuário que ele aceita é realmentejane
.O servidor se conecta ao PostgreSQL usando um nome de usuário/senha fixo (ou Kerberos ou o que você quiser), autenticando-se no servidor db como o usuário
webui
. O servidor db confiawebui
para autenticar seus usuários, portantowebui
, recebeuGRANT
s apropriados (veja abaixo).Nessa conexão o servidor usa
SET ROLE jane;
para assumir o nível de autorização do usuáriojane
. Até queRESET ROLE;
ou outroSET ROLE
seja executado, a conexão está operando com os mesmos direitos de acesso quejane
eSELECT current_user()
etc reportarájane
.O servidor mantém a associação entre a conexão do banco de dados em que se encontra
SET ROLE
ejane
a sessão web do usuáriojane
, não permitindo que essa conexão PostgreSQL seja utilizada por outras conexões com outros usuários sem um novoSET ROLE
meio.Agora você está autenticando fora do servidor, mas mantendo a autorização no servidor. Pg precisa saber quais usuários existem, mas não precisa de senhas ou métodos de autenticação para eles.
Ver:
SET SESSION AUTHORIZATION
SET ROLE
GRANT
Detalhes
O servidor webui controla a execução das consultas e não permite a
jane
execução de SQL bruto (espero!), Portantojane
, não pode ser feitoRESET ROLE; SET ROLE special_admin_user;
pela interface do usuário da web. Para maior segurança, eu adicionaria um filtro de instrução ao servidor que rejeitouSET ROLE
eRESET ROLE
, a menos que a conexão estivesse ou entrasse em um pool de conexões não atribuídas.Você ainda está livre para usar autenticação direta para Pg em outros clientes; você pode misturar e combinar livremente. Você apenas tem que dar
GRANT
aowebui
usuário os direitos deSET ROLE
usuários que podem fazer login via web e, em seguida, dar a esses usuários quaisquerCONNECT
direitos normais, senhas, etc. que desejar. Se você quiser torná-los apenas na web,REVOKE
seusCONNECT
direitos no banco de dados (e depublic
).Para facilitar essa divisão de autenticação/autorização, tenho uma função especial para
assume_any_user
cadaGRANT
usuário recém-criado. Em seguida, chegoGRANT assume_any_user
ao nome de usuário real usado por coisas como um front-end da Web confiável, dando a eles o direito de se tornarem qualquer usuário que desejarem.É importante criar
assume_any_user
umaNOINHERIT
função, para que owebui
usuário ou o que quer que seja não tenha privilégios próprios e só possa atuar no banco de dados quando forSET ROLE
para um usuário real. Sob nenhuma circunstância devewebui
ser um superusuário ou proprietário do banco de dados .Se você estiver fazendo um pool de conexões, poderá usar
SET LOCAL ROLE
para definir a função somente dentro de uma transação, para que possa retornar as conexões ao pool apósCOMMIT
ouROLLBACK
. Cuidado, issoRESET ROLE
ainda funciona, então ainda não é seguro deixar o cliente executar qualquer SQL que desejar.SET SESSION AUTHORIZATION
é a versão relacionada, mas mais forte deste comando. Não requer associação de função, mas é um comando apenas de superusuário. Você não deseja que sua interface do usuário da web se conecte como um superusuário. Ele pode ser revertido comRESET SESSION AUTHORIZATION
,SET SESSION AUTHORIZATION DEFAULT
ouSET SESSION AUTHORIZATION theusername
para recuperar os direitos de superusuário, para que também não seja uma barreira de segurança que reduza os privilégios.Um comando que funcionasse como
SET SESSION AUTHORIZATION
, mas fosse irreversível e funcionaria se você fosse um membro da função, mas não um superusuário, seria ótimo. Neste ponto, não há um, mas você ainda pode separar autenticação e autorização muito bem se for cuidadoso.Exemplo e explicação
Agora conecte como
webui
. Observe que você não pode fazer nada,test_table
mas pode e ,SET ROLE
em seguida , pode acessar :jane
test_table
Observe que pode
webui
, mesmo quando já foi dado e mesmo que não tenha sido autorizado a assumir a função . define seu ID de usuário efetivo, mas não remove sua capacidade de outras funções, isso é uma propriedade da função à qual você se conectou, não sua função efetiva atual. Conseqüentemente, você deve controlar cuidadosamente o acesso aos comandos e . Não há, AFAIK, nenhuma maneira de obter uma conexão permanente , tornando-se verdadeiramente o usuário-alvo, embora certamente seja bom ter.SET ROLE
jim
SET ROLE
jane
jane
GRANT
jim
SET ROLE
SET ROLE
SET ROLE
RESET ROLE
SET ROLE
Comparar:
para:
Isso significa que
SET ROLE
não é exatamente o mesmo que fazer login como uma determinada função, algo que você deve ter em mente.webui
não podeSET ROLE
,dbowner
pois não foiGRANT
editado corretamente:portanto, por si só, é bastante impotente, só pode assumir os direitos de outros usuários e somente quando esses usuários tiverem acesso à web ativado.