Como você lida com a segurança do banco de dados de um aplicativo da área de trabalho?

12

Por cerca de 10 anos, trabalhei em vários aplicativos clientes de desktop internos com repositórios de dados do SQL Server. Raramente iniciei esses projetos - a maioria é trabalho de aquisição.

Uma coisa que parecia constante em todos os lugares foi que havia uma única conta de usuário global do SQL Server que esse aplicativo usava que concedia permissão ao banco de dados comum e sim, em algumas situações ingênuas, usava a saconta de usuário, que geralmente tentava corrigir quando possível .

Você não pode ocultar efetivamente esse nome de usuário e senha que o aplicativo usa para acessar o banco de dados. Eles são geralmente armazenados em um iniou configarquivo, ou, eventualmente, cozido no executável em si. Em todos os casos, eles ficam visíveis para o usuário se eles fizerem uma pequena escavação. Em um caso, na verdade, usamos um configarquivo, mas o criptografamos, mas é claro que a chave de criptografia tinha que ser armazenada no executável (não éramos ingênuos às limitações disso, mas efetivamente impedia as pessoas de bisbilhotar quem era esperto o suficiente procurar nos configarquivos).

Todos esses sistemas tinham um sistema de autenticação de usuário embutido no aplicativo, mas é claro que todos foram gerenciados pelo próprio aplicativo, o que significa que as informações do usuário foram armazenadas no banco de dados. O aplicativo restringia o que você poderia fazer com base no seu nível de acesso, mas é muito discutível se você puder se conectar ao banco de dados e executar consultas ad-hoc.

Estou interessado em saber o que outros sistemas fazem para solucionar esse problema. Aqui estão as opções que eu conheço:

  1. Use o mecanismo de segurança do SQL Server para manter uma lista de usuários e funções e fazer com que o aplicativo da área de trabalho adicione e remova usuários por meio de consultas T-SQL.
  2. Em vez de se conectar diretamente ao banco de dados, crie algum tipo de serviço da web que seja executado no servidor e coloque a lógica de autenticação. Faça todas as solicitações de validação de segurança.

As primeiras opções são um pouco feias porque você está separando os usuários do banco de dados, de modo que os usuários não são mais entidades de primeira classe e não é possível referenciá-los com relacionamentos de chave estrangeira etc.

O segundo parece ser um grande problema de desempenho e muito trabalho extra, além de você não poder usar com facilidade os mapeadores ORM como o NHibernate (eu acho).

Alguém tem experiência com isto? Melhores Práticas?

Editar

Pensando um pouco mais, a autenticação do SQL Server pode realmente resolver esse problema? Por exemplo, se o usuário precisar inserir e atualizar registros do quadro de horários para que você possa editá-lo, não há como o SQL server proibir o acesso a outras linhas na tabela de detalhes do quadro de horários, o que significa que você também pode ler e escrever quadros de horários de outras pessoas.

Scott Whitlock
fonte
Sobre o tópico de ligações; não usar ORM como o NHibernate é (eu acho) um problema não. Se você usar serviços da Web como exemplo, encontrará várias maneiras de vincular seus dados com eficiência ao XML.
jasonk
Você não deve usar seu ORM como um mapeamento direto entre objetos de negócios e entidades de banco de dados, é uma abordagem ruim que cria interfaces frágeis. Faça solicitações para uma camada de negócios que obtém entidades de banco de dados brutas e retorna apenas os dados necessários para o cliente.
Gbjbaanb
@gbjbaanb - claro, vou mudar toda a arquitetura esta tarde. :)
Scott Whitlock
Eu suponho que você poderia esperar até que alguém hacks-lo antes de mudá-lo, mas o lado bom, pelo menos, então você não terá problemas para obter o seu chefe para financiar o :-) arquitetar re-
gbjbaanb
Você pode impedir que um usuário atualize os registros de outra pessoa - usando um procedimento armazenado como a única maneira de atualizar os registros e usando o usuário que está executando o proc como parte da consulta. Veja CURRENT_USER
gbjbaanb

Respostas:

9

Receio que adicionar uma camada de serviço da Web seja provavelmente a solução correta para o seu problema.

A separação do cliente da implementação do banco de dados subjacente provavelmente também o ajudará a longo prazo.

Adicionar uma camada de serviço da web não necessariamente prejudica o desempenho ...

De fato, com uma API apropriada, um serviço da Web pode realmente melhorar o desempenho, agrupando várias consultas ao banco de dados na LAN do datacenter, em vez de exigir várias viagens de ida e volta pela WAN.

E, é claro, uma camada de serviço da Web geralmente pode ser dimensionada horizontalmente e adicionar armazenamento em cache apropriado às consultas do banco de dados, talvez até um mecanismo de notificação de alterações.

Uma camada de servidor adiciona segurança que você não pode garantir com os aplicativos em execução em um cliente remoto. Tudo o que é executado em um cliente pode ser "hackeado" e realmente não deve ser considerado de maneira alguma confiável. Você só deve realmente colocar a lógica de apresentação no cliente e hospedar qualquer coisa importante no hardware do qual tenha controle total.

Não sei sobre seus aplicativos, mas meus aplicativos da web são naturalmente divididos em várias camadas, com o código de apresentação separado da camada de persistência por pelo menos um nível de lógica de negócios que mantém os dois separados. Acho que isso facilita muito o raciocínio sobre meu aplicativo e é muito mais rápido adicionar ou modificar a funcionalidade. Se as camadas forem separadas de qualquer maneira, é relativamente fácil manter a camada de apresentação no cliente e o restante em um servidor sob meu controle.

Portanto, enquanto você pode resolver seus problemas sem introduzir uma camada de "serviço da Web", quando tiver escrito todos os procedimentos armazenados (ou equivalentes) necessários para preencher os buracos na implementação padrão de segurança do banco de dados, você provavelmente estaria melhor escrevendo um aplicativo do lado do servidor para o qual você pode escrever testes de unidade adequados.

Bill Michell
fonte
Concordo que ele não precisa ser um gargalo de desempenho, mas certamente adiciona uma camada extra à arquitetura, o que significa muito mais manutenção.
Scott Whitlock
3
Ele adiciona uma camada, mas não necessariamente manutenção. Considere que, com toda a lógica colocada no serviço, e não o cliente, as alterações podem ser 'implementadas' sem exigir que os usuários atualizem seus aplicativos clientes.
GrandmasterB
5

Semelhante à resposta de jmoreno, você pode negar ao usuário o acesso a tudo, exceto as permissões EXECUTE nos procedimentos armazenados, e aproveitar o encadeamento de propriedade para que o procedimento armazenado execute as operações necessárias nas tabelas.

Consulte aqui para detalhes https://msdn.microsoft.com/en-us/library/bb669058(v=vs.110).aspx

Quando o usuário digita seu nome de usuário / senha no lado do cliente, eu os armazeno e os envio como parâmetros para cada chamada de procedimento armazenado. Você pode verificá-los em relação aos valores armazenados em uma tabela antes de executar a operação desejada.

Definitivamente, não é a última palavra em segurança, mas pode ser necessária se seus PCs tiverem logons genéricos, limitando sua capacidade de usar grupos do AD para obter permissões ou se você tiver acesso limitado ao próprio AD.

James K
fonte
2

Uma abordagem é usar grupos de anúncios e procedimentos armazenados para limitar o que o usuário pode fazer - por exemplo, o banco de dados da planilha de horas, pode permitir inserir, atualizar e excluir as horas dos usuários, mas não a atualização das horas de mais ninguém. O ID do usuário seria fornecido pelo mecanismo do banco de dados, o usuário não teria acesso direto às tabelas do banco de dados, apenas aos sps que executavam consultas com base em seu ID de login.

Claro que isso nem sempre é viável, mas pode ser. A melhor abordagem dependerá de seus requisitos e recursos.

jmoreno
fonte
Isso é algo que eu não tinha considerado. Não tenho certeza se é um ótimo ajuste, mas funcionaria.
Scott Whitlock
1

O que você sugere como 'serviço da web' é chamado de arquitetura de n camadas . Geralmente, é o caminho a seguir nos casos em que problemas de segurança ou configuração são prováveis ​​(por exemplo, distribuição de um aplicativo em muitos escritórios). Porém, ele não precisa ser baseado na Web. Muitos trabalham com outros protocolos.

Você cria um servidor de aplicativos para atuar como intermediário entre o cliente e o banco de dados (e outros recursos). O servidor de aplicativos lida com a autenticação baseada em aplicativo e executa ações em nome do cliente. De fato, idealmente, você não faria nenhum SQL em seu cliente - em vez disso, chama métodos no servidor de aplicativos. O servidor de aplicativos lidaria com toda manipulação de dados.

Há vários benefícios na abordagem. Você não precisa configurar conexões e drivers de banco de dados nos clientes. Você não armazena usuários, senhas e servidores de banco de dados. A configuração dos clientes nem é necessária - basta apontá-los no código para o URL ou endereço certo. Além disso, com a 'lógica' no servidor de aplicativos, você não precisa se repetir ao desenvolver outros aplicativos - o mesmo servidor de aplicativos pode ser reutilizado por diferentes tipos de clientes.

GrandmasterB
fonte
Melhor ainda, se (ou quando) alguém invadir sua área de trabalho (ou servidor da Web em um equivalente baseado na Web), o invasor poderá ter acesso total ao sistema operacional, mas ainda não terá acesso ao banco de dados. E, portanto, eles não podem executar o "select * from users" canalizado para um arquivo que eles retiram, quebram à vontade e deixam seu CEO explicar à mídia por que seu sistema seguro foi comprometido. Se você também usar sprocs no banco de dados que permite apenas o acesso à execução, o invasor também poderá invadir o servidor e ainda não conseguirá obter todo o banco de dados do usuário.
Gbjbaanb
1

A tecnologia mudou um pouco. Se você autentica cada usuário no próprio banco de dados e usa funções de banco de dados, agora pode usar o que é chamado de Exibição Atualizável para resolver esse problema, pelo menos no SQL Server.

Aqui está a aparência de uma exibição atualizável para uma tabela chamada SomeTableonde cada linha dessa tabela está vinculada a um funcionário. O funcionário deve poder ver as linhas vinculadas a eles e os membros da função de RH devem ver todas as linhas, por exemplo:

CREATE VIEW [dbo].[vwSomeTable]
AS
    SELECT SomeTable.*
    FROM SomeTable
        INNER JOIN Employee ON SomeTable.Employee_ID = Employee.Employee_ID
    WHERE Employee.Username = USER_NAME() OR IS_MEMBER('HR_Role')=1

GO

Então, o que você faz é conceder permissões de leitura (e possivelmente gravar) na view ( vwSomeTable) a todos os usuários e não dar permissões na tabela ( SomeTable).

Você pode testar isso assim:

EXECUTE AS USER = 'Some_Regular_Username'
SELECT * FROM vwSomeTable

... que devem retornar apenas suas linhas. Ou:

EXECUTE AS USER = 'Some_HR_Username'
SELECT * FROM vwSomeTable

... que retornará todas as linhas. Observe que você precisará das permissões de execução como (representação) para fazer esse teste.

As visualizações são atualizáveis, portanto, mesmo o usuário comum pode fazer isso, desde que a linha esteja vinculada à sua Employeelinha:

UPDATE vwSomeTable
SET SomeColumn = 5
WHERE SomeTable_ID = 'TheID'
Scott Whitlock
fonte
0

Usar autenticação baseada em certificado é a maneira "correta" de implementar uma conta sql compartilhada. O objetivo é eliminar o uso de senha para esse tipo de coisa.

Atualizar:

Suponho que não entendi a pergunta. Eu pensei que tinha a ver com tentar encontrar uma alternativa para colocar um nome de usuário e senha db em uma configuração de aplicativo ou fazer backup no próprio aplicativo.

Você pode eliminar o problema de gerenciar senhas em aplicativos usando certificados do lado do cliente. O certificado em si não é suficiente, você precisa ter um sistema de distribuição e gerenciamento capaz de operar como revogação de certificado.

Referência: http://en.wikipedia.org/wiki/Public-key_infrastructure

dietbuddha
fonte
Você pode fornecer mais algumas informações sobre isso? Parece que pode ser ortogonal à intenção da minha pergunta original, mas é interessante.
Scott Whitlock
0

Criando uma nova solução de segurança para desktop, optamos pela solução de serviço da web que tentarei descrever a seguir.

Compilamos os executáveis ​​de aplicativos de desktop em um ambiente separado dos desenvolvedores. E calcule um HASH daquele executável que é registrado no banco de dados.

Um serviço da web que fornece todas as informações necessárias para a execução do aplicativo, a senha do banco de dados, as informações da cadeia de conexão, as permissões do usuário, etc.

usamos o logon único do banco de dados por aplicativo e registramos os detalhes do usuário no banco de dados em variáveis ​​de sessão para poder auditar registros.

Uma DLL lida com toda a comunicação do aplicativo da área de trabalho ao serviço da Web, acessível apenas com um token incorporado à DLL.

Para poder obter a senha do banco de dados do aplicativo no serviço da Web, a DLL calcula o HASH dos chamadores da DLL em tempo de execução e passa como parâmetro para o serviço da Web que valida o token da DLL e o tempo de execução do executável calculou o HASH para aquele registrado quando foi implantado (o aplicativo está disponível apenas em uma única instalação compartilhada em rede).

Dessa forma, caímos é uma boa solução para o problema de segurança com o qual estamos mais preocupados e bem cientes de algumas falhas de design. Estamos quase terminando esta implementação e até agora estamos felizes com os resultados.

Editar: você pode substituir a ideia de hash usando assinaturas digitais e certificados X.509.

Vitor Arbex
fonte
1
Parece bastante óbvio onde está a flagrante falha de segurança. A DLL da qual você fala está no sistema do cliente e não há como o código do servidor verificar se está falando com uma cópia legítima da DLL ou com uma cópia pirateada / maliciosa / falsa. Você acabou de criar muito trabalho para si mesmo sem adicionar muita segurança, se houver, extra. Tudo o que uma pessoa mal-intencionada precisa é do token e do algoritmo, ambos na DLL para quem quiser procurar.
21314 Scott Scottlock
@ScottWhitlock, Sim, eu concordo. estamos tentando ofuscar a DLL e o tráfego passando por HTTPS. Estamos tentando melhorar isso, eu gostaria muito de contribuir para melhorá-lo. Mas essa solução já resolve muitos problemas do sistema atual, incluindo senhas de texto sem formatação armazenadas em arquivos de rede. Além disso, o webservice permite a reutilização de muitos códigos acessíveis por qualquer um dos idiomas do cliente que usamos aqui, incluindo clientes Delphi e Clipper (Harbour)!
Vitor Arbex
No seu sistema, o usuário efetua login e é presumivelmente autenticado pelo serviço da web. Assumindo o uso de HTTPS, isso não é bom o suficiente? Você não precisa confiar no software cliente, pois sabe que o usuário é quem eles dizem ser e controla o serviço da Web; portanto, verifique se o serviço da Web entrega apenas as informações que o usuário especificado está autorizado a ver. Mesmo que eles fizessem a engenharia reversa do cliente e escrevessem os seus, que danos poderiam causar? Somente seu serviço da web conhece a senha do banco de dados e isso deve ser seguro.
Scott Whitlock