I'm just trying to figure out exactly how much of my own security I need to implement on the server side when saving changes in Breeze. In particular, I'm thinking about how a malicious user could manually hack the SaveChanges request, or hack the javascript in the client, to bypass my normal business rules - for example, to maliciously alter foreign key IDs on my entities.
I want to understand exactly where I need to focus my security efforts; I don't want to waste time implementing layers of security that are not required.
I'm using Breeze with .net and Entity Framework on the server side.
Here's a trivial example. ObjectA
has a reference to an ObjectB
, and ObjectA
is owned by a particular User
. So, my database looks like this:
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
From this model, the security concerns I have are:
ObjectA
ObjectA
at Bob's ObjectB
.User_Id
on his ObjectA
to be Alice.The solution for (1) is trivial; I'll ensure that my SaveChanges method has an [Authorize]
attribute.
I can easily use Fiddler to build a SaveChanges request to reproduce issues 2 to 4 - for example, I can build a request which changes Alice
's ObjectA to point to Bob's ObjectB
. This is what the message content might look like:
"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"
}
}
}
],
As I'd expect, when no security is implemented on the server side, this persists the updated value for ObjectB_Id
into the database.
However, I've also confirmed that if there is no entry for ObjectB_Id
in the originalValuesMap
, then even if I change the value for ObjectB_Id
in the main body of the message it is NOT updated in the database.
So, I think this means that the general security rules I need to follow on the server are:
[Edited 4 July 2013 - rewritten for clarity]
In general:
For "Unchanged" properties (properties which are not also on the originalValuesMap):
For changed properties (properties which are also on the originalValuesMap):
Business rules may prevent particular properties being changed. If this is the case, we should implement a check for each such rule.
If a value is allowed to be changed, and it is a foreign key, we should probably perform a security check to ensure that the new value is allowed to be used by the session identity
We must not use any of the original values in the originalValuesMap, as these may have been tampered with
[End of edit]
Assuming that these rules are correct, I guess there are a couple of options to implement security around the changed foreign keys:
originalValuesMap
; I'll need to go to the database (or other trusted source, eg session Cookie)Applying these rules to the security concerns that I gave above,
security concern (2). I'll need to check the user identity on the session against the User_ID
on the ObjectA
that is currently in the database. This is because I cannot trust the User_ID on the request, even if it is not in the originalValuesMap
.
security concern (3). If the business rules allow a change of ObjectB
, I will need to check who owns the new value of ObjectB_Id
; I'll do this by retrieving the specified ObjectB from the database. If this ObjectB
is not owned by ObjectA
's owner, I probably want to reject the changes.
security concern (4). If the business rules allow a change of User
, this is already covered by (2).
So, really, I'm looking for confirmation that I'm thinking along the right lines.
Phil ... you are absolutely on the right track here. You've done a nice job of laying out the issues and the threats and the general approach to mitigating those threats. It is almost as if you had written the introduction to the Breeze security chapter ... which we haven't gotten to yet.
I do not think that you are "over complicating things"
Someone reading this might think "wow ... that's a lot of work ... that Breeze stuff must be insecure".
Well it is a lot of work. But it isn't Breeze that is making it difficult. This is the necessary thinking for every web application in existence. Authentication is only the first step ... the easiest step ... in securing an application.
You shouldn't trust any client request ... even if the client is authenticated. That means making sure the client is authorized to make the request and that the content entering and exiting the server is consistent with what the client is both claiming to do and is allowed to do. These are general principles that apply to all web applications, not just Breeze applications. Adhering to these principles is no more difficult in Breeze than in any other technology.
One Breeze technicality you may have overlooked. The EFContextProvider.Context
should only hold the entities to save; don't use it to retrieve original entities.You'll need a separate DbContext
to retrieve the original entities to compare with the change-set entities from the client.
We are working on samples that demonstrate ways to handle the issues you described. For example, we're recommending (and demo'ing) a "validation rules engine" that plugs into the BeforeSaveEntitiesDelegate
; this "engine" approach makes it easier to write bunches of server-side rules and have them applied automatically.
Our samples and guidance aren't quite ready for publication. But they are coming along.
Meanwhile, follow your instincts as you've described them here. Blog about your progress. Tell us about it ... and we'll be thrilled to highlight your posts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With