在服务器上保护Breeze以防止恶意更新外键

时间:2013-07-04 13:40:26

标签: breeze

问题

我只想弄清楚在Breeze中保存更改时我需要在服务器端实现多少安全性。特别是,我正在思考恶意用户如何手动破解SaveChanges请求或破解客户端中的javascript,以绕过我的正常业务规则 - 例如,恶意更改我的实体上的外键ID。

我想确切地了解我需要关注安全工作的确切位置;我不想浪费时间实现不需要的安全层。

我在服务器端使用Breeze和.net以及Entity Framework。

实施例

这是一个微不足道的例子。 ObjectA引用了ObjectBObjectA归特定User所有。所以,我的数据库看起来像这样:

ObjectA:

Id    ObjectB_Id    SomeField          User_Id
1     1             Alice's ObjectA    1
2     2             Bob's ObjectA      2

ObjectB:

Id    SomeOtherField
1     Foo
2     Bar

User:

Id    Name
1     Alice
2     Bob

从这个模型中,我的安全问题是:

  1. 我不希望未经身份验证的用户更改任何数据
  2. 我不希望Bob能够对Alice的ObjectA
  3. 进行任何更改
  4. 我不希望Alice尝试将她ObjectA指向Bob的ObjectB
  5. 我不希望Bob尝试将User_Id上的ObjectA更改为Alice。
  6. (1)的解决方案是微不足道的;我确保我的SaveChanges方法具有[Authorize]属性。

    我可以轻松使用Fiddler构建一个SaveChanges请求来重现问题2到4 - 例如,我可以构建一个请求,将Alice的ObjectA更改为指向Bob的{{ {1}}。这就是消息内容的样子:

    ObjectB

    正如我所料,当服务器端没有实现安全性时,这会将"entities": [ { "Id":1, "ObjectB_Id":2, "SomeField":"Alice's ObjectA", "User_Id":1, "entityAspect": { "entityTypeName":"ObjectA:#MyNamespace", "defaultResourceName":"ObjectAs", "entityState":"Modified", "originalValuesMap": { "ObjectB_Id":"1" }, "autoGeneratedKey": { "propertyName":"Id", "autoGeneratedKeyType":"Identity" } } } ], 的更新值持久存储到数据库中。

    但是,我还确认,如果ObjectB_Id中的ObjectB_Id没有条目,那么即使我更改了originalValuesMap的主要内容它未在数据库中更新的消息。

    一般规则?

    所以,我认为这意味着我需要在服务器上遵循的一般安全规则是:

    [2013年7月4日修改 - 为清晰起见而重写]

    一般来说:

    • 消息中的任何内容都不可信任:原始值映射中的值也不应该是"不变的"值
      • 唯一的例外是实体的身份,我们可以认为这是正确的。
      • 据说"未改变"属性可能已被篡改,即使它们不在originalValuesMap

    For" Unchanged"属性(不在originalValuesMap上的属性):

    • 当"使用"任何"未改变"属性,我们不能使用消息中的值;我们必须从数据库中检索对象并使用其中的值。
      • 例如,在检查对象的所有权以确保允许用户更改它时,我们不能信任该消息的UserId;我们必须从数据库中检索实体并使用
      • 中的UserId值
    • 对于任何其他"不变的"物业,我们没有以任何方式使用,我们不必担心它是否被篡改,因为即使有,篡改的价值也不会持久存储到数据库

    对于已更改的属性(同样位于originalValuesMap上的属性):

    • 业务规则可能会阻止更改特定属性。如果是这种情况,我们应该对每个这样的规则进行检查。

    • 如果允许更改某个值,并且它是外键,我们应该执行安全检查以确保会话标识允许使用新值

    • 我们不得使用originalValuesMap中的任何原始值,因为这些值可能已被篡改

    [编辑完结]

    实施规则

    假设这些规则是正确的,我想有几个选项可以围绕更改的外键实现安全性:

    • 如果业务规则不允许更改特定字段,我将拒绝SaveChanges请求
    • 如果业务规则允许更改特定字段,我将检查是否允许新值。在这样做时,不能使用ObjectB_Id;我需要去数据库(或其他可信来源,例如会话Cookie)

    将这些规则应用于我上面提到的安全问题,

    • 安全问题(2)。我需要针对当前在数据库中的originalValuesMap上的User_ID检查会话中的用户身份。这是因为我无法信任请求中的User_ID,即使它不在ObjectA中。

    • 安全问题(3)。如果业务规则允许更改originalValuesMap,我需要检查谁拥有ObjectB的新值;我将通过从数据库中检索指定的ObjectB来完成此操作。如果此ObjectB_Id不归ObjectB所有者所有,我可能想拒绝这些更改。

    • 安全问题(4)。如果业务规则允许更改ObjectA,则(2)已涵盖此内容。

    问题

    所以,真的,我正在寻找确认我正在思考的问题。

    1. 我的一般规则是否正确?
    2. 我的规则实施听起来合理吗?
    3. 我错过了什么吗?
    4. 我过度复杂吗?

2 个答案:

答案 0 :(得分:2)

菲尔......你绝对走在正确的轨道上。您已经做好了布局问题和威胁以及减轻这些威胁的一般方法。这几乎就像你已经编写了Breeze安全章节的介绍......我们还没有这样做。

我不认为你“过于复杂化”

读过这篇文章的人可能会想“哇......那是很多工作......微风的东西一定是不安全的”。

这是很多工作。但是Breeze并不是让它变得困难。这是现有每个Web应用程序的必要思路。身份验证只是第一步......最简单的步骤......保护应用程序。

您不应该信任任何客户端请求...即使客户端已通过身份验证。这意味着确保客户端有权发出请求,并且进入和退出服务器的内容与客户端声称要执行和允许执行的内容一致。这些是适用于所有Web应用程序的一般原则,而不仅仅是Breeze应用程序。坚持这些原则在微风中并不比任何其他技术更难。

您可能忽略了一个微风技术性。 EFContextProvider.Context应该只保存要保存的实体;请勿使用它来检索原始实体。您需要单独的DbContext来检索原始实体,以便与客户端中的更改集实体进行比较。

我们正在研究样品,以展示处理您所描述问题的方法。例如,我们建议(和演示)一个插入BeforeSaveEntitiesDelegate的“验证规则引擎”;这种“引擎”方法可以更容易地编写一堆服务器端规则并自动应用它们。

我们的样本和指导尚未准备好发布。但是它们正在出现。

同时,按照你在这里描述的直觉行事。有关您进度的博客。告诉我们......我们很高兴能够突出你的帖子。

答案 1 :(得分:0)

我一直在寻找同一事项的指导,我很高兴找到你的精彩分析。在我看来,我们的问题的答案是不同的,假设我们正在讨论的应用程序将由多个模块组成,并且寿命超过一年。

如果规则变得过于复杂,则意味着我们可能会使用不恰当的方法。我相信很多优秀的开发人员都会应对这些规则,但令人遗憾的是,我们大多数同行要么弄错了,要么会在压力下忘记其中的一些。

我要说我们需要回到Fowler,Evans和Nilssons的出版物,并在他们之后重复说,在更大的应用程序中(这些具有强大的安全要求)实体模型不应该暴露给它客户端(除了安全性之外的其他原因 - 例如可维护性)。

另一方面,值得关注Greg Young和Udi Dahan后来提出的这些原创想法的修订。这些本质上说,阅读模型不一定也不常与写“数据”的模型相同。

总而言之,我要说基本规则应该是不要使用Breeze进行写作并将DO用于阅读(使用DTO /预测),前提是您不查询“真实”模型但是专为阅读而建的模型(例如视图而不是表格)。

如果您遵循您的域名和用例,并且最重要的是如果您遵循测试驱动方法,那么这一切都很自然地出现了。您是否真的会在遵循测试驱动开发的同时最终获得针对业务规则的BeforeSaveEntities解决方案?