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

Bin*_*ash 9 breeze

问题

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

我想准确理解我需要关注安全工作的重点; 我不想浪费时间实现不需要的安全层.

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

这是一个简单的例子.ObjectA有一个参考ObjectB,ObjectA并由一个特定的所有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
Run Code Online (Sandbox Code Playgroud)

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

  1. 我不希望未经身份验证的用户更改任何数据
  2. 我不希望鲍勃能够对爱丽丝做任何改变 ObjectA
  3. 我不想让爱丽丝试着把她指向ObjectA鲍勃的ObjectB.
  4. 我不希望鲍勃试图改变User_Id他的ObjectA爱丽丝.

(1)的解决方案是微不足道的; 我将确保我的SaveChanges方法具有[Authorize]属性.

我可以轻松地使用Fiddler构建一个SaveChanges请求来重现问题2到4 - 例如,我可以构建一个请求,它将AliceObjectA 更改为指向Bob的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"
            }
        }
    }
],
Run Code Online (Sandbox Code Playgroud)

正如我所料,当服务器端没有实现安全性时,这会将更新后的值保留ObjectB_Id到数据库中.

但是,我还证实,如果不存在用于入门ObjectB_IdoriginalValuesMap,那么即使我更改值ObjectB_Id的消息时,它是不是在数据库中更新的主体.

通用规则?

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

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

一般来说:

  • 消息中的任何内容都不可信任:原始值中的值既不是值,也不是"未更改"的值
    • 唯一的例外是实体的身份,我们可以假设这是正确的.
    • 假设"未更改"的属性可能已经被篡改,即使它们不在原始的ValueMap中

对于"未更改"属性(不在原始值上的属性):

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

对于已更改的属性(也在originalValuesMap上的属性):

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

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

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

[编辑完]

实施规则

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

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

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

  • 安全问题(2).我需要检查对会话的用户身份User_IDObjectA是目前在数据库中.这是因为我不能信任请求中的User_ID,即使它不在originalValuesMap.

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

  • 安全问题(4).如果业务规则允许更改User,则已由(2)涵盖.

问题

所以,真的,我正在寻找确认我正在思考正确的方向.

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

War*_*ard 2

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

我不认为你“让事情变得过于复杂”

读到这里的人可能会想“哇……工作量很大……Breeze 的东西一定不安全”。

嗯,这是很多工作。但让事情变得困难的并不是微风。这是现有的每个 Web 应用程序的必要思考。身份验证只是保护应用程序的第一步......最简单的一步......。

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

您可能忽略了 One Breeze 的技术细节。应该EFContextProvider.Context只保存要保存的实体;不要使用它来检索原始实体。您需要单独的方法DbContext来检索原始实体,以便与来自客户端的更改集实体进行比较。

我们正在制作示例来演示处理您所描述的问题的方法。例如,我们推荐(并演示)一个插入到的“验证规则引擎” BeforeSaveEntitiesDelegate;这种“引擎”方法使得编写大量服务器端规则并自动应用它们变得更加容易。

我们的示例和指南尚未准备好发布。但他们正在到来。

同时,遵循您在此描述的直觉。关于您的进展的博客。告诉我们这件事......我们将很高兴突出您的帖子。