我只想弄清楚在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)
从这个模型,我的安全问题是:
ObjectA
ObjectA
鲍勃的ObjectB
.User_Id
他的ObjectA
爱丽丝.(1)的解决方案是微不足道的; 我将确保我的SaveChanges方法具有[Authorize]
属性.
我可以轻松地使用Fiddler构建一个SaveChanges请求来重现问题2到4 - 例如,我可以构建一个请求,它将Alice
ObjectA 更改为指向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_Id
的originalValuesMap
,那么即使我更改值ObjectB_Id
的消息时,它是不是在数据库中更新的主体.
所以,我认为这意味着我需要在服务器上遵循的一般安全规则是:
[2013年7月4日编辑 - 为清晰起见而重写]
一般来说:
对于"未更改"属性(不在原始值上的属性):
对于已更改的属性(也在originalValuesMap上的属性):
业务规则可能会阻止更改特定属性.如果是这种情况,我们应该对每个这样的规则进行检查.
如果允许更改某个值,并且它是外键,我们应该执行安全检查以确保会话标识允许使用新值
我们不得在originalValuesMap中使用任何原始值,因为这些值可能已被篡改
[编辑完]
假设这些规则是正确的,我想有几个选项可以围绕更改的外键实现安全性:
originalValuesMap
; 我需要去数据库(或其他可靠的来源,例如会话Cookie)将这些规则应用于我上面提到的安全问题,
安全问题(2).我需要检查对会话的用户身份User_ID
的ObjectA
是目前在数据库中.这是因为我不能信任请求中的User_ID,即使它不在originalValuesMap
.
安全问题(3).如果业务规则允许更改ObjectB
,我将需要检查谁拥有新值ObjectB_Id
; 我将通过从数据库中检索指定的ObjectB来完成此操作.如果这ObjectB
不是由ObjectA
所有者拥有,我可能想拒绝这些更改.
安全问题(4).如果业务规则允许更改User
,则已由(2)涵盖.
所以,真的,我正在寻找确认我正在思考正确的方向.
菲尔……你绝对走在正确的道路上。您很好地列出了问题和威胁以及减轻这些威胁的一般方法。这几乎就像您已经编写了 Breeze 安全章节的介绍一样……我们还没有完成。
我不认为你“让事情变得过于复杂”
读到这里的人可能会想“哇……工作量很大……Breeze 的东西一定不安全”。
嗯,这是很多工作。但让事情变得困难的并不是微风。这是现有的每个 Web 应用程序的必要思考。身份验证只是保护应用程序的第一步......最简单的一步......。
您不应该信任任何客户端请求...即使客户端已通过身份验证。这意味着确保客户端有权发出请求,并且进入和退出服务器的内容与客户端声称要做的和被允许做的一致。这些是适用于所有 Web 应用程序的一般原则,而不仅仅是 Breeze 应用程序。在 Breeze 中遵守这些原则并不比在任何其他技术中更困难。
您可能忽略了 One Breeze 的技术细节。应该EFContextProvider.Context
只保存要保存的实体;不要使用它来检索原始实体。您需要单独的方法DbContext
来检索原始实体,以便与来自客户端的更改集实体进行比较。
我们正在制作示例来演示处理您所描述的问题的方法。例如,我们推荐(并演示)一个插入到的“验证规则引擎” BeforeSaveEntitiesDelegate
;这种“引擎”方法使得编写大量服务器端规则并自动应用它们变得更加容易。
我们的示例和指南尚未准备好发布。但他们正在到来。
同时,遵循您在此描述的直觉。关于您的进展的博客。告诉我们这件事......我们将很高兴突出您的帖子。