有什么理由不直接从客户端Javascript转到数据库吗?


62

可能重复:
编写Web“服务器少”应用程序

因此,假设我要构建一个Stack Exchange克隆,然后决定使用CouchDB之类的东西作为我的后端存储。如果我使用它们的内置身份验证和数据库级别授权,是否有任何理由不允许客户端Javascript直接写入可公开使用的CouchDB服务器?因为这基本上是一个CRUD应用程序,并且业务逻辑由“只有作者才能编辑他们的帖子”组成,所以我认为在客户端内容和数据库之间没有一层的必要性很高。我只是在CouchDB端使用验证,以确保没有人放入垃圾数据,并确保正确设置权限,以便用户只能读取自己的_user数据。渲染将通过类似于AngularJS的客户端完成。从本质上讲,您可能只拥有一个CouchDB服务器和一堆“静态”页面,因此一切顺利。您不需要任何类型的服务器端处理,而只需要一些可以处理HTML页面的内容即可。

向世界开放我的数据库似乎是错误的,但是在这种情况下,只要正确设置权限,我就无法想到为什么。这违背了我作为Web开发人员的本能,但我想不出一个很好的理由。那么,为什么这是个坏主意呢?

编辑:看起来这里有一个类似的讨论:编写Web“服务器少”应用程序

编辑:到目前为止,很棒的讨论,我感谢大家的反馈!我觉得我应该添加一些通用假设,而不是专门调用CouchDB和AngularJS。因此,我们假设:

  • 数据库可以直接从其隐藏存储对用户进行身份验证
  • 所有数据库通信都将通过SSL进行
  • 数据验证可以(但不应这样做)由数据库处理
  • 除了管理员功能外,我们关心的唯一授权是仅允许某人编辑自己的帖子
  • 每个人都可以读取所有数据(除了可能包含密码哈希的用户记录之外),我们非常满意
  • 管理功能将受到数据库授权的限制
  • 没有人可以将自己添加为管理员角色
  • 数据库相对容易扩展
  • 真正的商业逻辑几乎没有,甚至没有。这是一个基本的CRUD应用

不完全是纯粹的“数据库客户端”,但是您看过Parse和Firebase吗?(也包括流星),它们都有一些相关的概念,并且都以创新的方式处理安全性。如看到这一点:blog.firebase.com/post/38234264120/...
伊兰棉兰

是! 我之前听说过Parse,但没有听说过Firebase。非常有趣,而且绝对符合我的想法。
克里斯·史密斯

您的数据库如何防止从JavaScript发送SQL注入或XSS?从客户端发送的几乎所有东西都必须假定它是不安全的,那么该数据库中有哪些规定可以用来过滤数据以确保其有效并使用准备好的语句插入数据?
zuallauz 2012年

6
忽略其他所有内容,您将创建一个2层应用程序,该应用程序将UI与数据库紧密耦合。除非您的应用程序微不足道,否则这并不是一个好主意。
安迪

12
SSL不会阻止某人运行DELETE FROM ImportantData;
user253751 '16

Answers:


48

根据您的建议进行操作会在客户端语言和数据库之间建立紧密的耦合。

可以-编写和维护的代码更少,并且理论上调试可以/应该更快一些。

另一方面,这使其他方面更加困难。如果/当您需要更改这些技术中的任何一种时,由于它们之间的紧密联系,您将很难过。

保护自己免受攻击将(相当)困难。您假设客户端将始终向数据库提出格式正确的请求。假定没有人会破解客户端代码以插入恶意语句。换句话说,他们将“借用”您的身份验证机制,并用其替换常规的客户端代码。

我不推荐这样做,许多人会强烈地告诉你不要这样做。但这是可以做到的。


有趣。攻击者如何借用我的身份验证机制?我不会信任客户端进行身份验证。数据库只需将HTTPS POST传递到会话端点,该会话将对POSTed密码进行哈希处理并检查其是否有效。如果是的话,它将返回一个会话cookie,以在将来的请求中使用。
克里斯·史密斯

1
我只需要会话cookie,对不对?我使用您的客户端进行身份验证并获取我的会话cookie。然后,我偷的会话cookie与我的客户端,并将涨得厉害格式的请求造成严重破坏。请记住,这些全都在我的机器上了,所以我什至不需要MiTM攻击。

7
@ChrisSmith-只要您觉得自己正在解决安全问题,就可以处理对您建议的主要异议。如果您已解决他们的问题或认为自己愿意,那就去吧。您问题的简单形式是:您问为什么人们不使用ABC。主要的答案是安全性和紧密耦合。解决这些问题并消除代码。

2
更不用说您没有地方可以缓存经常请求的数据,因此您每次都必须访问数据库。当然,也许您的数据库驱动程序做了一些缓存,但是它的可调性如何?它会跨线程共享吗?
TMN 2012年

1
我不满意允许通过Web客户端通过直接sql语句直接访问我的sql数据库,因为您永远不知道它们将发出什么类型的请求。他们将运行删除,更新或插入语句吗?如果这样做,他们是否会提供您的应用程序期望的数据?会发生意外删除吗?意外的数据库更改通常会破坏您的应用程序。最好最小化发送到数据库的命令,以便您可以更轻松地清理收到的输入,以便您的应用程序有更好的机会正常工作。
内森·皮林

36

这可能不是一个好主意。我可以给出的第一个也是最强烈的理由是,数据库服务器并非设计为公共Web服务器。相反,传统观点认为您应该将数据库隐藏在防火墙后面。

如果您需要支持证据,则有很多问题-并非所有都无法克服,但还有很多要考虑的问题。以下不分先后顺序:

  • 它无法执行查询清理,因为您是直接向其发送查询
  • 数据库权限的工作方式往往不同于Web服务器和应用程序的权限。Web服务器和应用程序框架从零开始,您需要显式创建和公开各个资源,端点和操作。另一方面,数据库要求您授予较高级别的角色。
  • 它可能无法很好地优化以承受Web服务器的工作量。您无法从连接池中受益。
  • 较流行的Web服务器已分解为很多。而且他们已经收到了很多安全补丁。您的DBMS基本上被设计为隐藏在防火墙之后,因此它可能尚未经过公用网络上可能面临的潜在威胁的一小部分的测试。
  • 必须使用数据库的查询语言来保护私有数据。根据您的DBMS,这可能具有挑战性。
  • 必须使用数据库的查询语言来过滤大型数据集-无论如何,您可能会努力做到;但是对于更复杂的业务规则而言,这可能会变得很繁重。
  • 对第三方库的支持有限或不支持。
  • 对您将遇到的许多问题的社区支持非常有限(可能为零)。

...而且我敢肯定还有其他问题。我敢肯定,对于大多数问题,即使不是所有这些问题,也都有解决方案。但是,有一个列表可以帮助您入门!


1
这里有一些值得深思的食物。并非所有这些要点都适用于所有情况,并且同样重要,但是拥有一个简明扼要的要点清单很重要,这很重要。谢谢!
Dav

16

我能想象的最好的单一原因是:因为任何参与方都不直接支持或推荐此方法。

浏览器供应商,EcmaScript标准,数据库系统开发人员,网络设备公司,托管/基础架构设计师和安全专家均未积极支持(甚至可能考虑)您提出的用例。这是一个问题,因为您提出的方法需要所有这些实体(甚至更多)才能适合您的应用程序,即使所涉及的系统都不是为此目的而设计的。

我并不是说不可能。我只是说这不像“重新发明轮子”,而更像是重新发明基于浏览器的客户端-服务器交互。

充其量,您将要做很多工作,甚至使系统在尽可能最基本的水平上运行。现代流行的数据库不是基于REST的,也不是基于HTTP的,因此您将构建自己的基于WebSocket的客户端驱动程序。

即使使一切在技术上都能正常工作,您也将放弃现代体系结构的许多最强大功能。您将无需深入防御-每个人都可以轻松地直接连接到大多数网站黑客尝试的主要目标。但是您提出的方案远不止于此。

提出的模型不仅公开服务器,还公开有效的连接字符串。攻击者不能仅对服务器执行ping操作,而是可以主动登录并向其发送命令。即使可以限制数据访问,我也不知道DBMS系统中有足够的工具来防止拒绝服务方案及其类似情况。当使用增强型SQL(例如TSQL)进行操作时,通常很容易产生无限有效地运行的炸弹(一些不受限制的联接可以产生笛卡尔积,并且您将拥有一个SELECT,它将永远运行,完成繁重的工作) 。我以为您需要禁用SQL的大多数功能,甚至使用JOIN消除基本的SELECT查询,也许只允许调用存储过程?我什至不知道您是否可以做到,我从未被要求尝试过。它没有

数据库可伸缩性也往往是大规模工作中最困难的问题之一,而向外扩展多个HTTP服务器-特别是具有静态或缓存页面的扩展-是最容易的部分之一。您的建议通过基本上负责100%的服务器端活动来使数据库完成更多工作。这本身就是一个致命的缺陷。通过将工作移到客户端上所获得的收益,是通过将更多的工作移到数据库上而失去的。

最后,我想指出的是,您提出的建议的核心不是新的,而是可以追溯到几十年前。该模型称为“胖数据库”模型,正如您所建议的,该模型基本上将大多数服务器端逻辑移至数据库中。该模型在大众互联网上被淘汰的原因有很多,而自己深入研究该历史可能会很有帮助。还要注意,即使那样,也几乎没有考虑过让完全不受信任的用户能够登录到系统并运行命令,因为仍然可以控制访问以选择不应被不断攻击系统的内部(已知)用户。

事实是,您仍然需要HTTP服务器来提供文件,因为数据库系统根本不这样做。同时,可以通过使用瘦服务器模型(例如使用Nodejs)将RESTful接口公开给数据库来获得您建议的所有内容。这之所以流行是有原因的-它可以正常工作,将数据库隐藏在保护层的后面,具有极高的可伸缩性,但仍允许您根据需要构建任意大小的数据库。


8

因为这基本上是一个CRUD应用程序,并且业务逻辑由“只有作者才能编辑他们的帖子”组成,所以我认为在客户端内容和数据库之间没有一层的必要性很高。我只是在CouchDB端使用验证来确保没有人放入垃圾数据,并确保权限设置正确,以便用户只能读取自己的_user数据。

好吧,将您的授权(安全性问题)和逻辑验证放在远离数据库的位置, 可以在软件系统中分离问题。因此,您可以测试,维护,扩展和重用逻辑代码块,从而降低了破坏系统功能的风险。

为客户输入提供直接与数据库通讯的能力具有破坏数据的巨大潜力

这也意味着避免/消除紧密的耦合会使您的软件系统更易于维护和更可靠。


1
我通常会对此表示同意,但是我可以像在服务器端一样轻松地测试,维护和扩展客户端代码中的代码块。不使用适当的关注点分离并不是用Java来做所有事情。我只是将实际处理从服务器移至客户端。那么在购买我之间有什么层次呢?
克里斯·史密斯

2
进行客户端验证对于客户端来说是一件好事,但是在服务器端进行验证比以往任何时候都更为关键。因为,您的客户端请求可以轻松模拟。进行逻辑分隔和/或分层有助于社交性和可维护性。
EL Yusubov

因此,扮演魔鬼的提倡者:正如我在下面提到的,我可以使用CouchDB的验证功能来确定所提交的数据是否有效。每当您尝试添加或更新文档时,它都会检查您是否被允许使用以及其格式是否正确。它在数据库方面进行了更多处理,但是它相当轻巧,无论如何我都需要考虑扩展数据方面。这不能解决问题吗?
克里斯·史密斯

不,我不这么认为。一旦记录数量开始增长并且您在系统上获得了更多的用户,将验证和授权逻辑放入数据库将严重影响系统性能。
EL Yusubov

DB引擎旨在存储和检索数据,而不是操纵或验证数据。当然,您可以按照自己的方式来做,但这并不是遵循的有效方式。
EL Yusubov

6

让用户直接与数据库交互对我来说确实很危险。

CouchDB的身份验证机制真的如此复杂,以至于您只能将用户的读写访问权限仅隔离于应该读写的数据上(我们所讨论的是按文档访问,甚至是按文档字段访问)特权)?多个用户共享的“公共”数据呢?这在您的应用程序设计中根本不存在吗?

您是否真的希望用户能够以任何方式更改其数据?例如,如何进行XSS注入?在它们进入数据库之前,有一个服务器层来筛选它们会更好吗?


1
您提出了一些要点,我也有同样的想法。我得出的结论是,在此(假设的)应用程序中,任何人都可以读取除用户记录以外的内容,我可以接受。他们只能写入最初创建的文档(这是我上面提到的唯一“业务逻辑”)。CouchDB似乎可以通过其内部_users数据库和验证功能来完成这两项操作。
克里斯·史密斯

6

您有多种原因,但还有更多原因:面向未来。随着应用程序的发展,迟早会有一些要求,这些要求在客户端JS或数据库中的存储过程中无法轻易或安全地实现。

例如,您被告知所有新注册都需要具有验证码才能有效。使用几乎所有现代Web应用程序框架,这将非常容易。只需在注册表单上拍一个reCAPTCHA,将reCAPTCHA的响应令牌传递回后端,然后向后端添加几行代码,以使用Google API验证令牌的有效性(或者更好的是,使用其他人编写的库来执行此操作)为了你)。

如果您使用的是两层系统,并且依赖于数据库来获取所有服务器端逻辑,那么如何验证令牌?是的,我想理论上可以根据DBMS编写存储过程,该存储过程以某种方式调用shell并使用适当的参数调用curl。这几乎也肯定是一个可怕的想法:输入过滤和防范安全漏洞将是可怕的。您将在处理错误处理和超时方面一团糟;而且您必须自己解析响应。更不用说DBMS并非打算这样做,因此没有理由认为性能,稳定性,线程安全性等都不会成为问题。例如,参见这个线程,它讨论了Postgres的一些问题。

而这仅仅是在表单中添加一个简单的验证码的问题。如果要添加SMS验证,或向不活动的用户发送电子邮件以提醒他们有关您的应用程序的后台作业,或添加文件上传功能以便人们可以设置个人资料图片,该怎么办?也许您决定有一天您的应用程序应该进行一些自动化测试?还是您想跟踪版本控制系统中过程的更改?有许多库和工具可用于大多数有用的语言来为您处理其中的大多数任务,但您的DBMS几乎没有可用的库和工具,因为这并不是要这样做。

最终,您将想要做一些您无法直接在DBMS中合理地做的事情,然后您将被困住。因为您已经在DBMS中构建了整个应用程序,所以除了添加一个简单的功能之外,您别无选择,只能获得一个Web服务器并开始用另一种语言来重建各个部分。

那真是太遗憾了,因为我们已经为放置应用程序逻辑的地方命名,并且出于某种原因,它被称为“您的应用程序的源代码”而不是“数据库存储过程”。


5

如果您的客户端javascript中包含您的安全检查和业务逻辑,则恶意用户可能会覆盖它们。作为替代方案,您可以利用基于JavaScript的服务器端技术(例如Node.JS)来处理验证,授权等。


身份验证和授权将由数据库本身处理,因此在这方面我完全不会信任客户端。CouchDB具有内置的验证功能,每当您尝试更新文档时,这些功能就会触发,因此我将使用这些功能来检查所提交的内容是否有效。
克里斯·史密斯

2

您可能希望确保的任何业务约束都应在服务器端进行验证。即使您控制用户访问,某些人也可能发送无效数据。

以下是您的stackoverflow克隆示例:

  • 无论如何,您如何阻止网站上的“封闭式”问题被编辑?
  • 您如何防止人们删除评论?
  • 您如何防止他人伪造评论日期?
  • 您将如何防止人们在同一篇文章中发表50篇文章?
  • 如果您多挖掘一点,可能还有更多示例。

任何人都可以操纵客户端代码并完全侵犯数据完整性(即使仅限于某些对象,例如他们自己的帖子)。


1

在Firebug中编辑页面,并在某处添加类似于以下内容的行:

ExecDbCommand("DROP TABLE Users")

运行。

编辑:

问题实际上是关于CounchDB的,因此没有sql可以在此处运行。但是想法是一样的。我认为任何不重要的应用程序都依赖于数据,以遵守由应用程序代码检查/强制执行的某些一致性规则。恶意用户可以修改客户端代码,以违反您的业务规则的形式保存数据,并可能在您的应用程序中造成严重破坏。

如果您的站点从业务角度认为所有可能的数据状态都是有效的,则一定要走这条路,但是(如果并非如此)那么,您将希望保证所存储的任何数据都是由生成的根据您的规则编码


CouchDB不知道该怎么办,但我明白你的意思。如果权限设置正确,则对此类事件的响应将是“ 401未经授权”。
克里斯·史密斯

-1,发布SQL代码时,您甚至什至不知道CouchDB是什么。而且,仅通过在CouchDB上创建一个管理员帐户,您就已经阻止了其他任何用户执行最危险的操作。
菲利普

很公平。我跳过了问题中有关CouchDB的部分,仅将其注册为“直接从客户端JS访问数据存储”。我将编辑回复。
AZ01 2012年

1
+1,无论是否使用SQL,他的观点仍然成立。可以使用JS调试器来更改数据的访问方式。
GrandmasterB 2012年

1

我知道这是一个老问题,但是我想补充一下,因为我的经验与其他答案完全不同。

我已经花了很多年编写实时的协作应用程序。这些应用程序的一般方法是在本地复制数据,并与对等体尽快同步更改。对数据的所有操作都是本地的,因此所有数据存储,数据访问,业务逻辑和用户界面都是本地的。“离线优先”运动(http://offlinefirst.org/)已采用这种方法来构建离线Web应用程序,并且可能具有一些相关资源。这些用例不仅要求您向客户端开放数据访问层,而且还要求数据存储!我知道我知道。看起来疯了吧?

对于此类脱机优先应用程序的关注与您所要求的类似,只是删除了一个级别。这似乎与我有关。假设您要开放对客户端的直接数据访问,问题就变成了,如何限制恶意用户的影响?好了,有很多策略,但是如果您来自更传统的开发背景,这些策略就不那么明显了。

第一个误解是公开数据库意味着公开所有数据。以CouchDB为例;CouchDB中的数据库是轻量级的,因此您无需再考虑在服务器上创建成千上万个单独的数据库。用户只能以读取器或写入器的身份访问被授予访问权限的数据库(更不用说验证功能和CouchDB的功能),因此他们只能访问数据的子集。

第二个误解是用户对数据的限制是一个问题!如果为用户提供了数据库的副本,则他们可以随意删除所有数据库而不会影响其他用户。但是,您应该先验证它们的更改,然后再将其数据复制回“中央”存储。考虑一下Git-用户可以在分支,分支和本地存储库中执行任何操作,而不会影响master分支。合并回主人涉及很多仪式,而不是盲目地完成。

我目前正在使用CouchDB构建一个系统,其中用户需要在数据上进行协作以构建数据集,然后通过QA / QC工作流程“发布”该数据集。协作是在数据副本(我们称为暂存数据库或工作数据库)上进行的,一旦完成,负责人员将对数据进行质量检查/质量控制,然后将其复制回主存储库。

由此带来的许多好处是其他系统难以实现的,例如,对于传统的三层CRUD应用程序而言,版本控制,复制和协作(可离线工作!)非常困难。

我的建议-如果您的应用程序是“传统”应用程序,则以传统方式进行。如果我上面提到的任何事情(尽管还有很多……)适用于您,请考虑使用其他体系结构,并准备好横向思考。


0

我认为,鉴于您的所有假设,直接从客户端转到数据库是可行的。但是,有理由考虑一下您的假设是否有效,并且将来可能会继续保持这种假设。

我担心将来所有人都无法读取所有数据,尤其是将来可能开发更多的业务逻辑。如果项目成功,这两种可能性都更大。

只要您留有自己的方式来解决这些问题,并且将来确实需要解决这些问题,我认为您的设计就会奏效。我认为您需要格外小心,以区分JavaScript代码中的问题,并且其中的一些最终可能会稍后在服务器上重写。

但是,我绝对可以看到以后再进行测试的风险所在,而如今减少了活动部件的收益。


好点子。这绝对是一个狭窄的用例,因此您不能将其应用于任何应用程序。
克里斯·史密斯

0

首先感谢开箱即用的问题.... :)

但是我建议是:始终尝试保持3层之间的隔离。之类的是Presentation / Business和Database或DAO,因为这将是每天需要大量更改的那些需求和设置中的最佳实践。

在简单的世界中,您的Presentation层不应该知道数据库层,即某些日期类型字段的格式可能与Presentation层和数据库层不同,因此用户可以根据自己的需要自由选择合适的日期格式。

而且业务逻辑必须像表示层和数据库/ Dao层之间的耦合一样,如字段的转换,某些业务验证等,应在业务层而不是根据您的问题在Javascript部分中进行处理。

在复杂的场景,功能(甚至是复杂的验证)期间,这种隔离将为您提供极大的便利和便利。最大的优点是:您可以使用不同的技术来实现这些层,并且可以根据业务需求或范围进行更改。

谢谢


0

如果您想用JavaScript构建SQL并将其发送到数据库,以验证权限等,那么从安全性的角度来看,这将是一场灾难。仅仅是因为在构建API并自己构建查询时,您仅需要从安全性角度分析有限数量的查询。如果查询是在系统外部构建的,那么您可能会受到无限数量的欺骗。

但事实并非如此,因为您正在使用键值数据库(据我所知,CouchDB通常属于该类别)。数据库接口本身是一种中间层,并且由Apache团队出于安全原因对其进行了测试。由于JavaScript API相对简单,因此与JSF应用程序所具有的复杂接口相比,它甚至更易于分析潜在的缺陷。

如果您进行复杂的安全测试,这可能是一个安全的解决方案。当使用诸如JSF之类的框架时,这甚至会更加容易,而这些框架通常在后面使用几乎不可读的API。默默无闻的安全性无法解决。

关于您的问题,无论如何它都不是直接访问数据库。直接访问将是用JavaScript构建SQL查询(不幸的是,我已经看到了这样的解决方案)。在您的情况下,CouchDB本身提供了隔离层。您当然可以将其包装在API中以对其进行加固,但是只要您可以轻松地测试特定用户可以执行的操作以及安全约束是否对您有用,您将获得安全而强大的解决方案,而无需添加其他层。


0

我看到两个问题:

1.紧密耦合:更改数据库选项?好了,现在您也必须更改所有客户端代码。相信我。在客户端,我们不需要更多问题。

2. TMI安全问题:过多地揭示了工作原理。Auth可能仍然是一个障碍,但是当您确切地知道服务器端正在发生什么时,发现漏洞利用就容易多了。

非常薄的中间层可能是更好的选择。


-1

如果javascript是唯一的数据库访问层,则如果禁用了javascript(或设备的浏览器不支持),则客户端将无法使用您的网络应用。


2
嗯,不要太担心这一点。无论如何,现在大多数网络都依赖Javascript。我可能只需要打破<noscript>标记,并告诉他们如果他们希望我的网站(和其他网站的80%)正常工作,就需要打开它。
克里斯·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.