Project type: Asp MVC 2/NHibernate/C#
Problem
If you have an edit page in an web application you will come to the problem that you have to send and then receive the id of the entity you're editing, the IDs of sub-entities, entities that can be selected by dropdownmenus,...
As it is possible to modify a form-post, an evil user could try to send back another ID which maybe would grant him more rights (if i.e. that ID was related to a security entity).
My approach
Create a GUID and associate it with the ID
Save the association in the http session
Wait for the response and extract the real ID out of the received GUID.
Question:
What techniques do you use to obfusicate an entity-ID?
If you're doing that much for GUIDs, why not just use GUIDs for the identity of the entity itself that's actually stored in the database (though I'd advise against it)?
Or you could have a server side encryption scheme that encrypts and then subsequently decrypts the id (this is a long the same lines as what you're doing except you're not storing anything random like this in the session (yuck :) ).
You could even forget trying to do this at all since a lot of sites are "affected" by this issue, and it's obviously not a problem (StackOverflow for example). The overhead is just too much.
Also, if you're worried about security, why don't you have some sort of granular permissions set on the individual action/even entity level. This would solve some problems as well.
EDIT:
Another problem with your solution is inconsistent unique identifiers. If a user says "ID as23423he423fsda has 'invalid' data", how do you know which ID it belongs to if it's changing on every request (assuming you're going to change the id in the URL as well)? You'd be much better of with an encryption algorithm that always hashes to the same value therefore, you can easily perform a lookup (if you need it) and also the user has consistent identifiers.
Your controllers should be immune to modified POST data. Before displaying or modifying records belonging to a user, you should always check whether the records in question belong to the authenticated user.
Related
Up until now, in my MVC applications, every time I wanted to get a resource I would include the database id in the URI.
Example: Imagine an application that have products, one of those products has the id 1, I could access the product details on the uri products/1
However this may be a issue, imagining that the id could change. Even if you argue that id is the primary key and it wouldn't change, users could still gain knowledge that 1 was in fact the product id and it is used to access the database. Could this possibly may come a security issue?
Despite of this, there is a dependency between the uri and how the database is structured.
(How) can I make a uri that isn't database dependent and still access that resource?
Just add a key field to the DB table(s) which is unique. When you look up the data select your rows by that field instead of the ID. No, this really isn't any more secure but it is easy to do if you'd like to. One reason to do this which is valid is for pretty URLs.
UPDATE:
Putting any feature on a website is inherently less secure than not putting it there. You are basically asking, 'Is it less secure to provide the ability to reference specific items in my DB from the web?'. The answer to that is yes but that doesn't mean that you shouldn't do it. It means that if you want to do it you'll need to be careful and make sure that your site is secure. Does it know that the person trying to access that resource is who they claim they are? If it does and if we've decided that means they should get access then we can say it is secure. The ability to access a resource is a feature; not a security hole.
We currently have a website with user login.
We have a user table with userId.
We now want users to have a duplicate profile, that is entirely seperate from their main profile. This needs to be a secret profile.
Now we could just add two records into the db, but the id's would be sequential (until we hit a high hit rate of signups) so a user could workout that a userId would be related to one ID higher.
I realise this is not an ideal solution, but it is a late change to a big software project so we are trying to be as pragmatic as possible, while requiring as little code change as possible.
Options:
Turn off auto increment Ids, and build our own keyGeneration table. Start one table at 0, and start the secret one at 1000000000. We then can then turn off auto incrementing ID's in the user table, and use these keys.
The problem is, does having keys running, 1,1000000000,2,1000000001,3,1000000002 cause a massive indexing problem? Would we have to force index rebuilds all the time?
We key a seperate table just for the 2nd profile id's, again starting at 10000000000. We then modify all our code to check for id's > 999999999 and flip the logic on the server side so the lookups work correctly.
Means doing that check everywhere a user ID is passed into the site, from the front end.
As we don't do that too much, (we obviously mainly grab userId of logged in user securely, it might not be that bad.
Anyway, just wondering if anyone has any thoughts on this?
///////Edit
To put this into further context, imagine on stackoverflow or facebook, you have 2 profiles that you can control, that have no link between them. Like the way multiple users on Facebook can all act as a Page account, yet there is no link back from that account to the real user profile.
Essentially to not break referential integrity or re write too much code, I really want to pass an ID (int) back down to the front end for these account. Then the whole system just keeps ticking over as it has done.
Guid could be cool! But it would have a performance overhead (NOT THAT I CARE ABOUT THAT REALLY ;) but it would also mean writing a lot of code to handle Guids being what is passed to the front end (not that we rely on front end variables being right) but that is why I suggest the high int solution above. As we still have ASP.NET Membership lurking in the background I almost thought that could be good but A) we plan to remove that one day (or migrate to simple membership) b) we use sequential Guid generation in our user table for performance (sorry again to talk about optimization, before it's needed)
Guid, randon numbers by a web service. Plenty of solutions. I would rather go with a GUID.
THAT SAID: This is a business key, i would still use an autoincrement style technical key for referential integrity.
Here is my situation:
I have a search page that pulls data from a database. Each record shown has a key attached to it in order to pull data from the database for that record. When a link to a document for a record is clicked, this key is added on to the URL using KO data-bind and control is passed to the corresponding MVC Controller.
Here is my problem:
That key is displayed in the URL. I cannot allow that. A user of this website is only allowed access to certain records. It is unacceptable if the user is able to see any record simply by changing the last number or two of the key in the URL. The best solution I've come up with so far is to use AES256 encryption to encrypt each key as the search results are processed, then decrypt after the encryption is passed to another controller. This works great except when I get to the environment where HTTPS is used. I get 400 errors.
Am I over-thinking this? Is there a way, using MVC and KO, to mask the key from the URL entirely? Or should the encryption be allowed in the URL even when using HTTPS?
Here are some examples for clarification:
Without any changes to my code, here is how a URL would look:
https://www.website.com/Controller/Method/1234
Using encryption, I come up with something like this:
https://www.website.com/Controller/Method/dshfiuij823o==
This would work fine as long as it works with HTTPS.
One way or another, I need to scramble the key in the URL or get rid of it. Or determine a way to not run a search with the key every time the controller is called.
Thank you all for any help.
Unless I'm missing something really obvious here, can't you, on the web service side of things, check the if the logged in user has the correct permissions to the record and, if not, don't show the record?
This should ideally be done at the searching level so the user doesn't see any of the files they can't get access to anyway. And even if they change the keys in the browser, they still won't have access.
If there is no membership system, then there's going to need to be one implemented if you really want to make your site secure. Otherwise, you're playing with fire. Otherwise, you're going to need to set your documents to "public" or "private", in which will still require a database-level change.
Edit
If you really need to make your ID's unguessable, don't encrypt them, go for something a lot more simple and create GUIDs for them at your database level. Then your URL would contain the GUID instead of an encrypted key. This would be a lot more efficient due to you not having to encrypt/decrypt your record IDs on every call.
This, however, is still not 100% secure and I doubt would pass PCI Data Security checks as people can still look at (and copy/paste) GUIDs from the query string, just as easy as they could with encrypted strings. Realistically, you need a membership system to be fully compliant.
I agree with thedixon. You should be checking that a user has permission to view any of the items anyway.
I also agree that using GUIDs is a good idea.
However, if you're suck with ints as ids, here's a simple approach: when creating the URL: multiply the id by a large integer, such as 12345. Then when processing a request, divide the number in the URL by your "secret" number. It isn't fool-proof. But a person guessing would only have a tiny chance of getting a real ID--specifically, a 1 in 12345 chance of getting a real ID.
So I have never had to use cookies before but now I am making a Shopping Cart that they can keep coming back to and leaving but I want it to store what they added.
What I am wondering:
How do check if a cookie exists and then create or update it, is that the best way to think about using a cookie?
How exactly would I store the data, in particular I want to store a list of IDs like "5,6,7,8", should I just use one string for this or is there a faster/better way than reading/parsing/writing something like that? I mean I suppose I would just keep adding new_value + ',' to the end, is there an append for cookie variables?
Does the cookie have some unique identifier that I would use to be sure I don't write duplicates or something?
Note: It's easy to look up 'HOW' like for seeing the syntax but I'm really trying to grasp the 'BEST WAY' or most ideal, how it was meant to be used, or how all you programmers found is the most fruitful way to utilize them in this type of scenario.
The winning answer to this similar question suggests that you only store the user ID in the cookie. The rest goes in the database.
If you can consider other approaches besides cookies, many folks prefer using session over using cookies. For one thing, you don't always have a lot of room in a cookie.
Storing the shopping cart in a cookie means that you will have no record of what people were shopping for but didn't purchase.
OTOH, using the cookie is using the shoppers' storage space and preserving your own. That could be significant over time and a lot of shoppers.
I solved this in the past by creating a class to manage the cookies (e.g.CookieManager) with static methods I passed an HttpRequest object to.
I was trying to solve a very similar problem, so I created a Count cookie and then a cookie which stored the information I wanted to save (in your case an ID number). I only wanted to save the last 5 items a user viewed, so I would manage this in my CookieManager class, dequeuing the oldest cookie and queuing up latest. The Count cookie kept track of how many cookies I had. Obviously, this isn't very high tech or secure, but for this project that was completely unnecessary. Anything you want to be robust should be saved on a database, or elsewhere server-side.
I want to further explain why you only store a guid that maps to a userid in a cookie. There are two main reasons:
Performance. As slow as it may seem to pull data from a database, you have to remember that cookie data is not free. It has to be uploaded from the user's browser to your web server, and even high-speed broadband connections tend to have much slower upload speeds. By contrast, your database likely has a gigabit link (sometimes even faster) directly to the web server. So what you really want in your cookie for best performance is a guid that maps directly to the primary key of your database table.
Security. Data in cookies is stored in a plain text file on the user's computer. You never know where a user will access your site from; it could be a very public place that's not appropriate to keep such data.
So is there any data you can use cookies for directly? As it happens, there is. Cookies have the nice property of sticking with a particular machine and browser. These days a lot of people will access the web from more than one place. Perhaps a work computer, a home computer, a smart phone, a netbook... all of which may have different screen sizes and other peculiarities. So what you can do with a cookie is store information specific to that combination of user+location.
I have a multi-user ASP.NET MVC application. The users are not supposed to see or do anything with each other's data.
One of my controller actions is the obligatory POST to /Edit to edit a record (e.g. a contact). Now here is my problem: What if somebody forges a simple POST to /Edit (which automatically model-binds to my contact class) and edits somebody else's information? As each record is identified by Id, all that would have to be done is make a fake POST with Id XXX and then record # XXX would be overwritten with whatever the attacker supplied. How can I stop this?
The only thing I thought of is fetching the original instance every time first from the DB, check that it is in fact within the user's scope of editable objects (the ones he'd usually see to edit) and only if that check passes to proceed with UpdateModel and committing the update changes.
Is there a better way?
Edit: This is not a Cross Site/CSRF attack. Another logged in user can do this.
Authorization for the view/page and authorization for the particular object are really two separate concepts. The best approach is problem to use an Authorize attribute in conjunction with the ASP.NET roles system to either grant or deny access to a given page. Once you have verified that the user has access to the page, then you can verify whether he has the permission he is requesting for the object on which he is requesting it. I use this approach in my application, and it works great. By using the Authorize filter first, it significantly improves performance since the actual object permission checking is a much heavier operation.
Also, I use a home brewed rules system to actually set and determine whether the user has access to the object. For example, in my system, administrators have full access to every object. (That's a rule.) The user who creates the objects has full access to the object (also specified by a rule). Additionally, a user's manager has full access to every thing his employees have access to (again specified by a rule.) My application then evaluates the object to see if any of the rules apply--starting with the lest complex rules first and then moving on to the more complex rules last. If any rule is positive, I discontinue rule evaluation and exit the function.
What you could do is exclude the ID in the model binding with this syntax:
public ActionResult Edit([Bind(Exclude="Id")] User userToEdit)
and then fetch the ID from the current logged in user instead, so that it is only the logged in user that can edit his own items and noone elses.
Loading the original record first and checking the owner sounds like a good approach to me. Alternatively you could add a hidden field containing the record ID and cryptrographically sign that field to make sure it can't be changed, or take the record ID, hash it using the user ID as a salt and check that (assuming you're using the membership providers you should use the provider unique ID, not the login name)
This question reminded me of an article that covers a similar issue (in light of URL manipulation attacks) that i had bookmarked. They deal with an authenticated user messing with the data of another user. You might find it useful:
link text
Edit: This link should be correct:
Prevent URL manipulation attacks