Possível duplicação:
Gravando aplicativos da Web "sem servidor"
Então, digamos que eu vou construir um clone do Stack Exchange e decido usar algo como o CouchDB como minha loja de back-end. Se eu usar a autenticação interna e a autorização no nível do banco de dados, existe algum motivo para não permitir que o Javascript do lado do cliente grave diretamente no servidor CouchDB disponível ao público? Como esse é basicamente um aplicativo CRUD e a lógica de negócios consiste em "Somente o autor pode editar sua postagem", não vejo muita necessidade de 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 garantir que alguém não esteja inserindo dados de lixo e para garantir que as permissões sejam definidas corretamente, para que os usuários possam ler apenas seus próprios dados _user. A renderização seria feita no lado do cliente por algo como AngularJS. Em essência, você pode apenas ter um servidor CouchDB e um monte de páginas "estáticas" e pronto. Você não precisaria de nenhum tipo de processamento no servidor, apenas algo que pudesse servir as páginas HTML.
Abrir meu banco de dados para o mundo parece errado, mas nesse cenário não consigo pensar no porquê, desde que as permissões sejam definidas corretamente. Isso vai contra o meu instinto como desenvolvedor web, mas não consigo pensar em uma boa razão. Então, por que isso é uma má ideia?
EDIT: Parece que há uma discussão semelhante aqui: Gravando aplicativos Web "sem servidor"
EDIT: Discussão impressionante até agora, e agradeço o feedback de todos! Sinto que devo adicionar algumas suposições genéricas em vez de chamar especificamente o CouchDB e o AngularJS. Então, vamos supor que:
- O banco de dados pode autenticar usuários diretamente de seu armazenamento oculto
- Toda a comunicação com o banco de dados aconteceria por SSL
- A validação de dados pode (mas talvez não deva?) Ser tratada pelo banco de dados
- A única autorização com a qual nos preocupamos, além das funções de administrador, é que alguém só pode editar sua própria postagem
- Estamos perfeitamente bem com todos que conseguem ler todos os dados (EXCETO registros de 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 dimensionar
- Há pouca ou nenhuma lógica de negócios verdadeira; este é um aplicativo CRUD básico
fonte
DELETE FROM ImportantData;
Respostas:
Fazer o que você sugere cria um forte acoplamento entre o idioma do lado do cliente e o banco de dados.
Isso pode ser bom - há menos código para escrever e manter e, em teoria, a depuração pode / deve ser um pouco mais rápida.
Por outro lado, torna outros aspectos mais difíceis. Se / quando você precisar alterar uma dessas tecnologias, terá mais dificuldade por causa do forte 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 ao banco de dados. Isso pressupõe que ninguém jamais invadirá 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, e muitos diriam veementemente que não. Mas isso pode ser feito.
fonte
Provavelmente não é uma ótima ideia. E a primeira e mais forte razão que posso dar é que um servidor de banco de dados não foi projetado para ser um servidor público da Web. Pelo contrário, a sabedoria convencional diz que você deve ocultar seu banco de dados atrás de um firewall.
Se você precisa de evidências, há muitas preocupações - nem todas intransponíveis, mas muitas em que pensar. Em nenhuma ordem específica, aqui estão alguns:
... E eu tenho certeza que existem 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!
fonte
O melhor motivo que posso imaginar é: porque esse método não é diretamente suportado ou recomendado por qualquer parte envolvida.
Os fornecedores de navegadores, os padrões EcmaScript, os desenvolvedores de sistemas de banco de dados, as empresas de equipamentos de rede, os arquitetos de hospedagem / infraestrutura e os especialistas em segurança não suportam ativamente (ou talvez considerem) o seu caso de uso proposto. Isso é um problema, porque o método proposto exige 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 é 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ê fará muito trabalho para que os sistemas funcionem no nível mais básico possível. Os bancos de dados populares modernos não são RESTful ou construídos para funcionar com HTTP; portanto, você criará seus próprios drivers de cliente baseados no WebSocket (presumo).
Mesmo se você conseguir que tudo funcione tecnicamente, você estará renunciando a muitos dos recursos mais poderosos das arquiteturas modernas. Você não terá defesa em profundidade - todos podem conectar-se facilmente diretamente ao alvo principal da maioria das tentativas de invasão de sites. Mas o cenário que você propõe é muito, muito pior que isso.
O modelo proposto não está apenas expondo o servidor - está expondo cadeias de conexão válidas. Os invasores não podem simplesmente executar ping no servidor - eles podem entrar ativamente e alimentar os comandos. Mesmo que você possa limitar o acesso aos dados, não conheço ferramentas suficientes nos sistemas DBMS para proteger dos cenários de negação de serviço e de seus tipos. Ao trabalhar em versões aprimoradas do SQL, como o TSQL, muitas vezes é trivialmente fácil produzir bombas que funcionam de forma infinita (algumas junções irrestritas para produzir um produto cartesiano e você terá um SELECT que funcionará para sempre, fazendo um trabalho pesado) . Eu imagino que você precisaria desativar a maioria dos recursos do SQL, mesmo eliminando consultas SELECT básicas com JOINs e talvez apenas permitir a chamada de procedimentos armazenados? Eu nem sei se você pode fazer isso, nunca me pediram para tentar. Não
A escalabilidade do banco de dados também tende a ser um dos problemas mais difíceis no trabalho em grandes escalas, enquanto o dimensionamento de vários servidores HTTP - especialmente com páginas estáticas ou em cache - é uma das partes mais fáceis. Sua proposta faz com que o banco de dados faça mais trabalho, sendo responsável por basicamente 100% da atividade do servidor. Essa é uma falha assassina por si só. O que você ganha ao mover o trabalho para o cliente perde, movendo mais trabalho para o banco de dados.
Por fim, gostaria de salientar que o coração do que você propõe não é novo, mas na verdade remonta décadas. Esse modelo é chamado de "banco de dados fat", que basicamente moveu a maior parte da lógica do servidor para o banco de dados, exatamente como você propõe. Há muitas razões pelas quais esse modelo foi esquecido na Internet de massa e provavelmente seria informativo investigar mais essa história. Observe também que, mesmo assim, havia pouca consideração em ter usuários completamente não confiáveis capazes de efetuar login no 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.
O fato é que você ainda precisará de um servidor HTTP para servir arquivos, pois 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 no Nodejs) para expor uma interface RESTful ao seu banco de dados. Isso é popular por um motivo - ele funciona, mantém o banco de dados oculto por trás das camadas de proteção, é extremamente escalável e ainda permite que você construa seu banco de dados com a espessura que você desejar.
fonte
Bem, afastar sua autorização (as preocupações de segurança) e a validação lógica do Database fornece separação de preocupações 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 potencial muito grande para estragar os dados .
Isso também significa que evitar / remover acoplamentos apertados torna seu sistema de software mais sustentável e SOLID.
fonte
Deixar o usuário interagir diretamente com o banco de dados parece realmente perigoso para mim.
O mecanismo de autenticação do CouchDB é realmente tão sofisticado que você pode isolar o acesso de leitura e gravação de um usuário apenas aos dados que ele deve ler e gravar (estamos falando de acesso por documento, talvez até por campo de documento privilégios aqui)? E os dados "comuns", compartilhados por vários usuários? Isso não existe no design do seu aplicativo?
Deseja realmente que o usuário possa alterar seus dados de QUALQUER maneira? E as injeções de XSS, por exemplo? Não seria melhor ter uma camada de servidor para filtrá-las antes que elas entrem no banco de dados?
fonte
Você obteve vários motivos, mas eis mais um: à prova de futuro. Mais cedo ou mais tarde, à medida que seu aplicativo evolui, você será apresentado a alguns requisitos que não podem ser alcançados com facilidade ou segurança no JS do lado do cliente ou como um procedimento armazenado no banco de dados.
Por exemplo, você foi informado de que todos os novos registros precisam ter uma verificação CAPTCHA para serem válidos. Isso seria realmente fácil o suficiente com praticamente qualquer estrutura de aplicativo da web moderna. Basta colocar 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 back-end para verificar a validade do token com a API do Google (ou melhor ainda, usar uma biblioteca que alguém escreveu para fazer isso) para voce).
Se você estiver usando um sistema de duas camadas e contando com o banco de dados para toda a lógica do servidor, como verificará o token? Sim, suponho que possa ser teoricamente possível, dependendo do DBMS, escrever um procedimento armazenado que de alguma forma chame um shell e invoque curl com os argumentos adequados. Essa também é quase certamente uma idéia horrível: a filtragem de entrada e a proteção contra vulnerabilidades de segurança seriam terríveis; você teria uma bagunça ao lidar com erros e tempos limite; e você teria que analisar a resposta você mesmo. Sem mencionar que um DBMS não se destina a fazer isso, então não há razão para pensar que desempenho, estabilidade, segurança de threads, etc ... não serão problemas. Veja, por exemplo, este tópico , que discute alguns desses problemas para o Postgres.
E esse é apenas o problema de adicionar um CAPTCHA simples a um formulário. O que você fará se desejar adicionar a verificação por SMS ou um trabalho em segundo plano que envie e-mail a 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 do perfil? Talvez você decida que seu aplicativo deve fazer 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 poucas ou nenhuma estarão disponíveis para o seu DBMS, porque não é para isso.
Eventualmente, você desejará fazer algo que não possa razoavelmente fazer diretamente no DBMS e ficará paralisado. Como você construiu seu aplicativo inteiro no DBMS, não terá outra alternativa a não ser obter um servidor da Web e começar a reconstruir peças em outro idioma, apenas para adicionar um recurso simples.
E isso seria uma pena, porque já temos um nome para o local em que você coloca a lógica do aplicativo e é chamado "código-fonte do aplicativo" em vez de "procedimentos armazenados no banco de dados" por um motivo.
fonte
Se suas verificações de segurança e lógica de negócios 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 servidor baseada em JavaScript (como Node.JS ) para lidar com validação, autorização e similares.
fonte
Qualquer restrição comercial que você queira garantir deve ser validada no lado do servidor. Mesmo se você controlar o acesso do usuário, alguém poderá enviar dados inválidos.
Seguindo o exemplo de clone do stackoverflow:
Qualquer um poderia manipular o código do lado do cliente e violar completamente a integridade dos dados (mesmo que restrito a determinados objetos, como suas próprias postagens).
fonte
Edite a página no firebug e, em algum momento, coloque uma linha semelhante a esta:
ExecDbCommand("DROP TABLE Users")
Executá-lo.
Editar:
A questão era de fato sobre o CounchDB, portanto, não é necessário executar sql aqui. No entanto, a ideia é a mesma. Eu presumiria que qualquer aplicativo não trivial depende de dados para respeitar algumas regras de consistência que são verificadas / aplicadas pelo código do aplicativo. Um usuário mal-intencionado pode modificar o código do cliente para salvar dados de uma forma que viole as regras de negócios e possa causar estragos no aplicativo.
Se o seu site considerar todos os possíveis estados de dados válidos do ponto de vista comercial, siga esse caminho, mas se esse não for o caso (provável), você deverá ter a garantia de que todos os dados armazenados serão gerados pelo seu código e de acordo com suas regras .
fonte
Uma pergunta antiga, eu sei, mas eu queria conversar porque minha experiência é bem diferente das outras respostas.
Passei muitos anos escrevendo aplicativos colaborativos em tempo real. A abordagem geral para esses aplicativos é replicar dados localmente e sincronizar as alterações com os pares o mais rápido possível. Todas as operações nos 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" ( http://offlinefirst.org/ ) adotou essa abordagem para criar aplicativos da web offline 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 para clientes, mas também armazenamento de dados! Eu sei eu sei. Parece loucura, certo?
As preocupações com esses aplicativos offline primeiro são semelhantes ao que você pediu, apenas um nível removido. Parece relevante para mim. Como você está abrindo o acesso direto a dados para os clientes, a pergunta é: 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 cenário de desenvolvimento mais tradicional.
O primeiro equívoco é que expor o banco de dados significa expor todos os dados. Veja o CouchDB, por exemplo; os bancos de dados no CouchDB são leves, portanto, você não teria um segundo pensamento sobre a criação de centenas de milhares de bancos de dados separados em um servidor. Os usuários podem acessar apenas bancos de dados aos quais é concedida permissão para acessar como leitor ou gravador (sem falar nos recursos de validação e o que não é do CouchDB), para que possam acessar apenas um subconjunto dos dados.
O segundo equívoco é que um usuário cagando nos dados é um problema! Se os usuários receberem uma réplica de um banco de dados, poderão fazer o que quiserem sem afetar outros usuários. Porém, você deve validar as alterações antes de replicar os dados novamente no armazenamento "central". Pense no Git - os usuários podem fazer o que quiserem em ramificações, bifurcações e repositórios locais sem afetar a ramificação principal. A fusão de volta ao mestre envolve muita cerimônia e não é feita às cegas.
Atualmente, estou criando um sistema usando o CouchDB, no qual os usuários precisam colaborar com os dados para criar um conjunto de dados que é "publicado" por meio de um fluxo de trabalho de controle de qualidade / controle de qualidade. A colaboração é realizada em uma réplica dos dados (chamamos isso de banco de dados de teste ou de trabalho) e, uma vez concluída, uma pessoa responsável executa o controle de qualidade / controle de qualidade dos dados e somente depois disso é replicada novamente no repositório principal.
Muitos benefícios advêm disso, difíceis de obter em outros sistemas - como controle de versão, replicação e colaboração (deixe o trabalho offline!) Para aplicativos CRUD tradicionais de três camadas, é super difícil.
Meu conselho - se o seu aplicativo for "tradicional", faça-o da maneira tradicional. Se qualquer uma das coisas que mencionei acima (embora exista muito mais ...) se aplique a você, considere arquiteturas alternativas e esteja preparado para pensar lateralmente.
fonte
Eu 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 no futuro.
Eu ficaria preocupado que, no futuro, talvez não seja correto que todos leiam todos os dados, e principalmente que isso possa desenvolver mais lógica de negócios no futuro. Ambos são mais prováveis se o projeto for bem-sucedido.
Contanto que você tenha uma maneira de lidar com esses problemas no futuro, quando e se realmente precisar lidar com eles, acho que seu design funcionará. Eu acho que você precisará ter um cuidado extra para separar as preocupações no código JavaScript, e algumas delas poderão ser reescritas no servidor posteriormente.
Mas eu definitivamente podia ver onde vale a pena correr o risco de fazer isso mais tarde vs. o benefício de menos peças móveis hoje.
fonte
Em primeiro lugar, obrigado pela pergunta FORA DA CAIXA .... :)
Mas o que eu sugeriria é; Sempre tente manter uma segregação entre suas três camadas. que são Apresentação / Negócios e Banco de dados ou DAO, porque essa será a melhor prática para esses tipos de requisitos e configurações nas quais haverá muitas alterações 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 da camada de banco de dados, para que o usuário possa ter a liberdade de selecionar o formato adequado da data conforme suas necessidades.
E a lógica de negócios deve agir como um acoplamento entre a camada de apresentação e a camada de banco de dados / Dao, como a projeção dos campos, algumas validações de negócios etc. devem ser tratadas na camada de negócios e não na seção Javascript, conforme sua pergunta.
Essa segregação fornecerá a você muita facilidade e comportamento durante cenários complexos, funcionalidades-es 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 o escopo do negócio.
obrigado
fonte
Se você deseja criar SQL em JavaScript e enviá-lo ao banco de dados, que verifica os direitos etc., do que por motivos de segurança, seria um desastre. Simplesmente porque quando você cria uma API e cria consultas por conta própria, precisa analisar 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, já que você está usando o banco de dados de valores-chave (por mais que eu entenda, o CouchDB geralmente se enquadra nessa categoria). A interface do banco de dados em si é uma espécie de camada intermediária e é testada por razões de segurança pela equipe do Apache. Devido à API JavaScript relativamente simples, é ainda mais fácil analisar possíveis falhas do que as 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, como ao usar estruturas como JSF, que geralmente usam API dificilmente legível. A segurança pela obscuridade não é considerada solução.
Em relação à sua pergunta, de qualquer maneira, não haverá acesso direto ao banco de dados. O acesso direto seria a construção de consultas SQL em JavaScript (infelizmente, eu já vi essas soluções). No seu caso, o próprio CouchDB fornece a camada de isolamento. É claro que você poderia envolvê-lo em sua API para fortalecê-lo, mas contanto que você possa testar facilmente o que um usuário específico pode fazer e se as restrições de segurança estiverem funcionando, você terá uma solução segura e robusta sem camadas adicionais.
fonte
Eu vejo dois problemas:
1. Acoplamento estanque: Altere sua opção de banco de dados? Bem, agora você também precisa alterar todo o seu código do lado do cliente. 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. A autenticação ainda pode ser um obstáculo, mas encontrar uma exploração é muito mais fácil quando você sabe exatamente o que está acontecendo no lado do servidor.
Uma camada intermediária muito muito fina pode ser o melhor caminho a percorrer.
fonte
Seu cliente não poderá usar seu aplicativo Web se o javascript estiver desativado (ou não for suportado no navegador do dispositivo) se o javascript for a única camada de acesso ao banco de dados.
fonte