问题
我只是想弄清楚在 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
从这个模型中,我的安全问题是:
- 我不希望未经身份验证的用户更改任何数据
- 我不希望 Bob 能够对 Alice 的
ObjectA
- 我不希望爱丽丝试图将她指向
ObjectA
鲍勃的ObjectB
。 - 我不希望 Bob 尝试将
User_Id
他的角色更改ObjectA
为 Alice。
(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"
}
}
}
],
正如我所料,当服务器端没有实现安全性时,这会将更新的值保存ObjectB_Id
到数据库中。
但是,我还确认,如果 中没有 for 条目ObjectB_Id
,originalValuesMap
那么即使我更改ObjectB_Id
消息主体中的值 for ,它也不会在数据库中更新。
一般规则?
所以,我认为这意味着我需要在服务器上遵循的一般安全规则是:
[2013 年 7 月 4 日编辑 - 为清楚起见重写]
一般来说:
- 消息中的任何内容都不可信:originalValuesMap 中的值和所谓的“未更改”值均不可信
- 唯一的例外是实体的身份,我们可以假设它是正确的。
- 假设“未更改”的属性可能已被篡改,即使它们不在 originalValuesMap 中
对于“未更改”属性(不在 originalValuesMap 上的属性):
- 当“使用”任何“未改变”的属性时,我们不能使用消息中的值;我们必须从数据库中检索对象并使用其中的值。
- 例如,当检查对象的所有权以确保允许用户更改它时,我们不能信任消息上的 UserId;我们必须从数据库中检索实体并使用其中的 UserId 值
- 对于我们没有以任何方式使用的任何其他“未更改”属性,我们不必担心它是否被篡改,因为即使被篡改,被篡改的值也不会被持久化到数据库中
对于更改的属性(也在 originalValuesMap 上的属性):
业务规则可能会阻止更改特定属性。如果是这种情况,我们应该对每个这样的规则进行检查。
如果允许更改值,并且它是外键,我们可能应该执行安全检查以确保会话身份允许使用新值
我们不能使用 originalValuesMap 中的任何原始值,因为这些值可能已被篡改
[编辑结束]
实施规则
假设这些规则是正确的,我想有几个选项可以围绕更改的外键实现安全性:
- 如果业务规则不允许更改特定字段,我将拒绝 SaveChanges 请求
- 如果业务规则允许更改特定字段,我将检查是否允许新值。在这样做时,不能使用
originalValuesMap
; 我需要访问数据库(或其他可信来源,例如会话 Cookie)
将这些规则应用于我上面给出的安全问题,
安全问题 (2)。我需要根据当前数据库中的用户身份检查会话中的用户
User_ID
身份ObjectA
。这是因为我无法信任请求中的 User_ID,即使它不在originalValuesMap
.安全问题 (3)。如果业务规则允许更改
ObjectB
,我将需要检查谁拥有 的新值ObjectB_Id
;我将通过从数据库中检索指定的 ObjectB 来做到这一点。如果这ObjectB
不属于ObjectA
的所有者,我可能想拒绝更改。安全问题 (4)。如果业务规则允许更改
User
,这已经包含在 (2) 中。
问题
所以,真的,我正在寻找确认我的想法是正确的。
- 我的一般规则是否正确?
- 我对规则的执行听起来合理吗?
- 我错过了什么吗?
- 我是不是把事情复杂化了?