Existe alguma razão para não ir diretamente do Javascript do lado do cliente para um banco de dados?

60

Então, digamos que eu crie um clone do Stack Exchange e decido usar algo como o CouchDB como meu armazenamento de back-end. Se eu usar sua autenticação integrada e autorização em nível de banco de dados, há alguma razão para não permitir que o JavaScript do lado do cliente grave diretamente no servidor CouchDB publicamente disponível? Como esse é basicamente um aplicativo CRUD e a lógica de negócios consiste em "Somente o autor pode editar seu post", não vejo muita necessidade de ter uma camada entre o material do lado do cliente e o banco de dados. Eu simplesmente usaria a validação no lado do CouchDB para ter certeza de que alguém não está colocando dados de lixo e certifique-se de que as permissões estejam definidas corretamente para que os usuários possam ler apenas seus próprios dados do usuário. A renderização seria feita no lado do cliente por algo como o AngularJS. Em essência, você poderia ter apenas um servidor CouchDB e um monte de páginas "estáticas" e pronto. Você não precisaria de nenhum tipo de processamento no lado do servidor, apenas algo que pudesse servir as páginas HTML.

Abrir meu banco de dados para o mundo parece errado, mas neste cenário não consigo pensar no motivo, desde que as permissões estejam definidas corretamente. Isso vai contra o meu instinto de desenvolvedor web, mas não consigo pensar em um bom motivo. Então, por que isso é uma má ideia?

EDIT: Parece que há uma discussão semelhante aqui: Escrevendo Web "server less" aplicações

EDIT: Discussão incrível até agora, e agradeço o feedback de todos! Eu sinto que devo adicionar algumas suposições genéricas ao invés de chamar o CouchDB eo AngularJS especificamente. Então vamos supor que:

  • O banco de dados pode autenticar usuários diretamente de seu armazenamento oculto
  • Toda a comunicação do banco de dados aconteceria por SSL
  • Validação de dados pode (mas talvez não deva?) ser manipulada pelo banco de dados
  • A única autorização de que nos importamos, exceto funções administrativas, é a permissão exclusiva de alguém para editar sua própria postagem
  • Estamos perfeitamente bem com todo mundo sendo capaz de ler todos os dados (EXCETO registros do usuário que podem conter hashes de senha)
  • As funções administrativas seriam restringidas pela autorização do banco de dados
  • Ninguém pode se adicionar a uma função de administrador
  • O banco de dados é relativamente fácil de escalar
  • Existe pouca ou nenhuma lógica comercial verdadeira; este é um aplicativo CRUD básico
por Chris Smith 19.12.2012 / 15:34
fonte

15 respostas

47

Fazer como sugere sugere criar um acoplamento (er) entre o idioma do cliente e o banco de dados.

Isso pode ficar bem - há menos código para escrever e manter, e, em teoria, a depuração poderia / deveria ser um pouco mais rápida.

Por outro lado, torna outros aspectos mais difíceis. Se / quando você precisar alterar qualquer uma dessas tecnologias, você terá mais dificuldade devido ao strong acoplamento entre elas.

Proteger-se contra ataques será (bastante) um pouco mais difícil. Você está assumindo que o cliente sempre apresentará solicitações bem formatadas para o banco de dados. Isso pressupõe que ninguém nunca hackear o código do lado do cliente para inserir instruções maliciosas. Em outras palavras, eles "emprestam" seus mecanismos de autenticação e substituem o código normal do cliente pelo deles.

Eu não recomendaria isso, e muitos diriam veementemente que você não deveria. Mas isso pode ser feito.

    
por 19.12.2012 / 15:54
fonte
36

Provavelmente não é uma ótima ideia. E a primeira e mais strong razão que posso dar é que um servidor de banco de dados não é projetado para ser um servidor web público. Pelo contrário, a sabedoria convencional diz que você deve esconder seu banco de dados atrás de um firewall.

Se você precisar de evidências de apoio, há muitas preocupações - nem todas intransponíveis, mas muitas em que pensar. Em nenhuma ordem particular, aqui estão alguns:

  • Não é possível realizar sanitização de consultas, porque você está enviando as consultas diretamente.
  • As permissões de banco de dados tendem a funcionar de maneira diferente das permissões de servidor e aplicativo da web. Servidores da Web e estruturas de aplicativos iniciam você sem nada e você precisa criar e expor explicitamente recursos, pontos de extremidade e ações individuais. Os bancos de dados, por outro lado, pedem que você conceda papéis em um nível alto.
  • Provavelmente não é bem otimizado para sustentar a carga de trabalho de um servidor da Web; você não pode se beneficiar do pool de conexões.
  • Os servidores da web mais populares foram divididos em muito . E eles receberam muitos patches de segurança. Seu DBMS foi basicamente projetado para se esconder atrás de um firewall, então provavelmente ele não foi testado nem por uma fração de um por cento das ameaças potenciais que ele enfrentará na web pública.
  • Você deve usar a linguagem de consulta do banco de dados para proteger dados privados. Dependendo do seu DBMS, isso pode ser um desafio.
  • Você deve usar a linguagem de consulta do banco de dados para filtrar grandes conjuntos de dados - algo que você pode se esforçar para fazer de qualquer maneira; mas algo que pode se tornar oneroso para regras de negócios mais complicadas.
  • Suporte limitado ou sem suporte para bibliotecas de terceiros.
  • Suporte comunitário muito limitado (potencialmente zero) para muitos dos problemas que você encontrará.

... e tenho certeza de que há outras preocupações. E tenho certeza de que há uma solução para a maioria - se não todas essas preocupações. Mas há uma lista para você começar!

    
por 19.02.2016 / 23:20
fonte
16

A melhor única razão que posso imaginar é: porque esse método não é diretamente suportado ou recomendado por qualquer parte envolvida.

Fornecedores de navegadores, padrões EcmaScript, desenvolvedores de sistemas de bancos de dados, empresas de equipamentos de rede, arquitetos de hospedagem / infraestrutura e especialistas em segurança não apoiam ativamente (ou talvez considerem) o caso de uso proposto. Isso é um problema, porque o método proposto requer que todas essas entidades - e mais - funcionem adequadamente para seu aplicativo, mesmo que nenhum dos sistemas envolvidos tenha sido projetado para suportar isso.

Não estou dizendo que não seja possível. Só estou dizendo que isso é menos como "reinventar a roda" e mais como reinventar a interação cliente-servidor baseada em navegador.

Na melhor das hipóteses, você estará fazendo uma tonelada de trabalho para fazer com que os sistemas funcionem no nível mais básico possível. Os bancos de dados populares modernos não são RESTful ou criados para funcionar via HTTP, então você estará construindo seus próprios drivers cliente baseados em WebSocket (eu presumo).

Mesmo que você consiga tudo para funcionar tecnicamente, estará desistindo de muitos dos recursos mais poderosos das arquiteturas modernas. Você não terá nenhuma defesa em profundidade - todos podem se conectar diretamente ao principal alvo da maioria das tentativas de invasão de sites. Mas o cenário que você propõe é muito, muito pior do que isso.

O modelo proposto não está apenas expondo o servidor - está expondo cadeias de conexão válidas. Os atacantes não podem simplesmente fazer ping no servidor - eles podem fazer login e alimentar ativamente os comandos. Mesmo que você possa limitar o acesso a dados, não tenho conhecimento de ferramentas suficientes em sistemas de SGBD para proteger de cenários de negação de serviço e de sua natureza. Ao trabalhar em versões aprimoradas do SQL, como TSQL, muitas vezes é trivialmente fácil produzir bombas que rodem com eficácia infinitamente (algumas associações irrestritas para produzir um produto cartesiano e você terá um SELECT que será executado para sempre, fazendo trabalho pesado) . Eu imagino que você precisaria desabilitar a maioria dos recursos do SQL, mesmo eliminando consultas SELECT básicas com JOINs e talvez apenas permitindo chamar procedimentos armazenados? Eu nem sei se você pode fazer isso, nunca me pediram para tentar. Não parece bom.

A escalabilidade do banco de dados também tende a ser um dos problemas mais difíceis de se trabalhar em grandes escalas, enquanto a expansão de vários servidores HTTP - especialmente com páginas estáticas ou armazenadas em cache - é uma das partes mais fáceis. Sua proposta faz com que o banco de dados trabalhe mais, sendo responsável por basicamente 100% da atividade do lado do servidor. Isso é uma falha assassina por si só. O que você ganha ao mover o trabalho para o cliente que você perde, movendo mais trabalho para o banco de dados.

Finalmente, gostaria apenas de salientar que o coração do que você propõe não é novo, mas na verdade vem de décadas. Esse modelo é chamado de modelo "banco de dados de gordura", que basicamente moveu a maior parte da lógica do lado do servidor para o banco de dados, exatamente como você propõe. Há muitas razões pelas quais esse modelo passou pelo caminho da internet em massa, e provavelmente seria mais informativo olhar mais para essa história. Note também que, mesmo assim, havia pouca consideração em ter usuários completamente não confiáveis capazes de acessar o sistema e executar comandos, pois o acesso ainda seria controlado para selecionar usuários internos (conhecidos) que não deveriam estar atacando o sistema constantemente. / p>

O fato é que você ainda precisará de um servidor HTTP para servir arquivos, já que os sistemas de banco de dados simplesmente não fazem isso. Ao mesmo tempo, tudo o que você propõe pode ser obtido usando um modelo de servidor thin (como o Nodejs) para expor uma interface RESTful ao banco de dados. Isso é popular por uma razão - ele funciona, mantém o banco de dados escondido atrás de camadas de proteção, é extremamente escalável e ainda permite que você construa seu banco de dados com a espessura ou a espessura que deseja.

    
por 20.02.2016 / 00:14
fonte
8

Since this is basically a CRUD application and the business logic consists of "Only the author can edit their post" I don't see much of a need to have a layer between the client-side stuff and the database. I would simply use validation on the CouchDB side to make sure someone isn't putting in garbage data and make sure that permissions are set properly so that users can only read their own _user data.

Bem, colocar sua autorização (as preocupações de segurança) e a validação lógica do Banco de Dados fornecem separação de interesses em seu sistema de software. Assim, você pode testar, manter, dimensionar e reutilizar seus blocos de códigos lógicos com menos riscos de frear a funcionalidade no sistema.

Fornecer capacidade para a entrada do cliente se comunicar diretamente com o Banco de Dados tem um grande potencial para estragar os dados .

Isso também significa que evitar / remover acoplamento strong torna seu sistema de software mais fácil de manter e sólido.

    
por 19.12.2012 / 15:54
fonte
6

Permitir que o usuário interaja diretamente com o banco de dados parece realmente perigoso para mim.

O mecanismo de autenticação do CouchDB é realmente tão sofisticado que é possível isolar o acesso de leitura e gravação de um usuário apenas aos dados que ele deve ler e escrever (estamos falando de documento por documento, talvez até mesmo por documento privilégios de acesso a campo aqui)? E os dados "comuns" que são compartilhados por vários usuários? Isso não existe no design do seu aplicativo?

Você realmente deseja que o usuário possa alterar seus dados de qualquer maneira? E quanto às injeções de XSS, por exemplo? Não seria melhor ter uma camada de servidor para filtrá-los antes que eles entrem no banco de dados?

    
por 19.12.2012 / 17:39
fonte
6

Você recebeu várias razões, mas aqui está mais uma: prova do futuro. Mais cedo ou mais tarde, à medida que sua aplicação evoluir, você será presenteado com algum requisito que não pode ser obtido de forma fácil ou segura no JS do lado do cliente ou como um procedimento armazenado em seu banco de dados.

Por exemplo, você informa que todos os novos registros precisam ter uma verificação de CAPTCHA para ser válida. Isso seria bastante fácil com praticamente qualquer estrutura de aplicativo da Web moderna. Basta aplicar um reCAPTCHA no formulário de registro, passar o token de resposta do reCAPTCHA de volta ao back-end e adicionar algumas linhas de código ao seu backend para verificar a validade do token com a API do Google (ou, melhor ainda, usar uma biblioteca que outra pessoa escreveu para fazer isso por você).

Se você estiver usando um sistema de duas camadas e confiando no banco de dados para toda a sua lógica do lado do servidor, como você vai verificar o token? Sim, suponho que seja teoricamente possível, dependendo do DBMS, escrever um procedimento armazenado que de alguma forma chame um shell e invoque o curl com os argumentos apropriados. Isso também é quase certamente uma ideia horrível: filtragem de entrada e proteção contra vulnerabilidades de segurança seriam terríveis; você teria uma bagunça lidando com o tratamento de erros e tempos limite; e você teria que analisar a resposta você mesmo. Sem mencionar que um SGBD não se destina a fazer isso, então não há razão para pensar que desempenho, estabilidade, segurança de thread, etc ... não serão problemas. Veja, por exemplo, este segmento , que discute alguns desses problemas para o Postgres.

E são apenas os problemas em adicionar um CAPTCHA simples a um formulário. O que você fará se quiser adicionar a verificação por SMS ou um trabalho em segundo plano que envia e-mails para usuários inativos para lembrá-los sobre seu aplicativo ou adicionar um recurso de upload de arquivo para que as pessoas possam definir uma foto de perfil? Talvez você decida que seu aplicativo deve ter alguns testes automatizados algum dia? Ou que você gostaria de acompanhar as alterações nos seus procedimentos em um sistema de controle de versão? Existem inúmeras bibliotecas e ferramentas para a maioria das linguagens úteis para lidar com a maioria dessas tarefas, mas pouco ou nenhum estará disponível para o seu DBMS, porque não é feito para isso.

Eventualmente, você vai querer fazer algo que você não pode fazer diretamente no seu DBMS, e então você estará preso. Como você construiu todo o seu aplicativo no DBMS, você não terá outra alternativa senão obter um servidor da Web e começar a reconstruir partes em outro idioma, apenas para adicionar um recurso simples.

E isso seria uma verdadeira vergonha, porque já temos um nome para o local em que você coloca a lógica do aplicativo e é chamado de "código-fonte do aplicativo" em vez de "procedimentos armazenados do banco de dados" por um motivo.

    
por 20.02.2016 / 05:11
fonte
5

Se as verificações de segurança e a lógica comercial estiverem contidas no javascript do lado do cliente, elas poderão ser substituídas por um usuário mal-intencionado. Como alternativa, você pode aproveitar uma tecnologia do lado do servidor baseada em JavaScript Node.JS ) para lidar com validação, autorização e afins.

    
por 19.12.2012 / 16:24
fonte
2

Qualquer restrição comercial que você queira assegurar deve ser validada no lado do servidor. Mesmo se você controlar o acesso do usuário, alguém poderá enviar dados inválidos.

Seguindo seu exemplo de clone stackoverflow:

  • Como você bloquearia as perguntas "fechadas" no site de serem editadas de qualquer maneira?
  • Como você impediria que as pessoas excluíssem comentários?
  • Como você impediria que as pessoas falsificassem as datas dos comentários?
  • Como você evitaria que as pessoas votassem 50 vezes na mesma postagem?
  • Provavelmente, há muito mais exemplos se você pesquisar um pouco mais.

Qualquer um poderia manipular o código do lado do cliente e violar completamente a integridade dos dados (mesmo se restrito a determinados objetos, como suas próprias postagens).

    
por 20.12.2012 / 06:33
fonte
1

Edite a página no firebug e, em algum momento, coloque uma linha semelhante a esta:

ExecDbCommand("DROP TABLE Users")

Execute.

Editar:

A questão era, na verdade, sobre o CounchDB, portanto nenhum sql deve ser executado aqui. No entanto, a ideia é a mesma. Eu presumo que qualquer aplicativo não trivial depende de dados para respeitar algumas regras de consistência que são verificadas / impostas pelo código do aplicativo. Um usuário mal-intencionado pode modificar o código do cliente para salvar dados em um formulário que viola suas regras de negócios e pode causar estragos em seu aplicativo.

Se o seu site considera todos os estados de dados possíveis válidos do ponto de vista comercial, então, por todos os meios, siga este caminho, mas se não for o caso (provável), você deve ter a garantia de que os dados armazenados sejam gerados pelo seu código e de acordo com suas regras .

    
por 19.12.2012 / 17:39
fonte
1

Pergunta antiga, eu sei, mas eu queria entrar em contato porque minha experiência é bem diferente das outras respostas.

Eu passei muitos anos escrevendo aplicativos colaborativos em tempo real. A abordagem geral para esses aplicativos é replicar os dados localmente e sincronizar as alterações com os pares o mais rápido possível. Todas as operações em dados são locais, portanto, todo o armazenamento de dados, acesso a dados, lógica de negócios e interface do usuário são camadas locais. O movimento "offline primeiro" ( link ) adotou essa abordagem para criar aplicativos da Web off-line e pode ter alguns recursos relevantes. Esses tipos de casos de uso não apenas exigem que você abra sua camada de acesso a dados aos clientes, mas também o armazenamento de dados! Eu sei eu sei. Parece maluco, né?

As preocupações com esses primeiros aplicativos off-line são semelhantes ao que você pediu, apenas um nível removido. Parece relevante para mim. Como você está abrindo o acesso direto aos dados para os clientes, a questão é: como você pode limitar os efeitos de um usuário mal-intencionado? Bem, existem muitas estratégias, mas elas não são óbvias se você vier de um contexto de desenvolvimento mais tradicional.

O primeiro equívoco é que expor o banco de dados significa expor todos os dados. Tome CouchDB por exemplo; os bancos de dados no CouchDB são leves, portanto, você não pensaria duas vezes sobre a criação de centenas de milhares de bancos de dados separados em um servidor. Os usuários só podem acessar os bancos de dados aos quais têm permissão de acesso como leitores ou gravadores (sem falar nos recursos de validação e no que não são do CouchDB), para que eles possam acessar apenas um subconjunto dos dados.

O segundo equívoco é que um usuário com dados ruins é um problema! Se os usuários receberem uma réplica de um banco de dados, poderão usar tudo o que quiserem sem afetar outros usuários. Mas, você deve validar suas alterações antes de replicar seus dados de volta ao armazenamento "central". Pense no Git - os usuários podem fazer o que quiserem em ramificações, garfos e repositórios locais sem afetar o ramo principal. Mesclar de volta ao mestre envolve muita cerimônia e não é feito às cegas.

Estou construindo um sistema atualmente usando o CouchDB, onde os usuários precisam colaborar em dados para construir um conjunto de dados que é "publicado" por meio de um fluxo de trabalho de QA / QC. A colaboração é realizada em uma réplica dos dados (chamamos isso de banco de dados temporário ou de trabalho) e, uma vez concluída, uma pessoa responsável realiza QA / QC nos dados e somente depois disso é replicada de volta no repositório principal. / p>

Muitos benefícios que são difíceis de alcançar em outros sistemas - como controle de versão, replicação e colaboração (deixar o trabalho off-line!) para aplicativos tradicionais CRUD de três níveis são super difíceis.

Meu conselho - se o seu aplicativo for "tradicional", faça da maneira tradicional. Se qualquer uma das coisas que eu mencionei acima (embora haja muito mais ...) se aplicam a você, então considere arquiteturas alternativas e esteja preparado para pensar lateralmente.

    
por 30.08.2018 / 04:40
fonte
0

Acho que, considerando todas as suas suposições, é possível ir diretamente do cliente para o banco de dados. No entanto, é razoável verificar se suas suposições são válidas e provavelmente permanecerão assim no futuro.

Eu ficaria preocupado se, no futuro, talvez não seja aceitável que todos leiam todos os dados e, especialmente, que possam desenvolver mais lógica de negócios no futuro. Ambos são mais prováveis se o projeto for bem sucedido.

Desde que você deixe uma maneira de lidar com esses problemas no futuro, quando e realmente precisar lidar com eles, acho que seu design funcionará. Eu acho que você precisará ter cuidado extra para separar as preocupações no código JavaScript, e algumas delas podem ser reescritas no servidor mais tarde.

Mas eu definitivamente poderia ver onde poderia valer o risco de talvez fazer isso mais tarde contra o benefício de menos partes móveis hoje em dia.

    
por 19.12.2012 / 19:14
fonte
0

Primeiramente, obrigado pela pergunta OUT OF THE BOX ....:)

Mas o que eu sugiro é; Sempre tente manter uma segregação entre suas 3 camadas. que são Apresentação / Negócios e Banco de Dados ou DAO, porque essa será a melhor prática nesses tipos de requisitos e configurações, onde haverá muitas mudanças todos os dias.

Em mundos simples, sua camada de Apresentação não deve saber sobre a camada de banco de dados, ou seja, o formato de alguns campos de tipo de data pode ser diferente da camada de apresentação e camada de banco de dados, para que o usuário possa ter liberdade para selecionar o formato adequado. necessidades.

E a Business Logic deve agir como um acoplamento entre camada de apresentação e banco de dados / camada Dao, como conversão dos campos, algumas validações de negócios, etc, deve ser tratada na Business Layer, e não na seção Javascript.

Essa segregação proporcionará a você grande facilidade e comportamento durante cenários complexos, funcionalidades e até validações complexas. A melhor vantagem é: você pode ter diferentes tecnologias para implementar essas camadas e pode ser alterado de acordo com as necessidades ou escopo de negócios.

Obrigado

    
por 20.12.2012 / 06:16
fonte
0

Se você quiser criar SQL em JavaScript e enviá-lo para o banco de dados, que verifica os direitos, etc., do que por motivo de segurança, seria um desastre. Simplesmente porque quando você cria uma API , e construir consultas você mesmo, você tem que analisar a partir do ponto de vista da segurança apenas o número limitado de consultas. Se as consultas forem criadas fora do seu sistema, você tem um número potencialmente ilimitado de truques que alguém poderia fazer.

Mas não é o caso desde que você está usando banco de dados de valor-chave (por mais justo que eu entenda, o CouchDB geralmente cai nessa categoria). A interface do banco de dados em si é um tipo de camada intermediária e é testada por motivos de segurança pela equipe do Apache. Por causa da API JavaScript relativamente simples, é ainda mais fácil analisar possíveis falhas do que interfaces complicadas que os aplicativos JSF possuem.

Esta pode ser uma solução segura, se você fizer testes de segurança complexos. Isso pode ser ainda mais fácil ao usar estruturas como o JSF, que geralmente usam APIs dificilmente legíveis. Segurança por obscuridade não é considerada solução.

Com relação à sua pergunta, não haverá acesso direto ao banco de dados de qualquer maneira. O acesso direto seria a construção de consultas SQL em JavaScript (infelizmente, eu vi essas soluções). No seu caso, o próprio CouchDB fornece a camada de isolamento. Você poderia, é claro, envolvê-lo em sua API para fortalecê-lo, mas contanto que você possa testar facilmente o que determinado usuário pode fazer e se as restrições de segurança estiverem funcionando, você terá uma solução segura e robusta sem camadas adicionais.

    
por 19.12.2012 / 19:46
fonte
0

Eu vejo dois problemas:

1. Acoplamento Apertado: Altera sua opção de DB? Bem, agora você tem que mudar todo o seu código do lado do cliente também. Confie em mim. Não precisamos de mais problemas no lado do cliente.

2. Problema de segurança da TMI: revela muito sobre como as coisas funcionam. O Auth ainda pode ser um obstáculo, mas encontrar um exploit é muito mais fácil quando você sabe exatamente o que está acontecendo no servidor.

Uma camada intermediária muito fina pode ser o melhor caminho a seguir.

    
por 20.12.2012 / 08:49
fonte
-1

Seu cliente não pode usar seu aplicativo da web se o javascript estiver desativado (ou não for compatível com o navegador do dispositivo dele) se o javascript for a única camada de acesso ao banco de dados.

    
por 19.12.2012 / 16:10
fonte