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.
Related
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.
I have a number of locations in a number of applications I have built where a page accepts a QueryString in the following format: http://localhost/MySite.aspx?ID=ab1cbabe-42e2-4d15-ab11-17534b829381
These pages will then take the query string, attempt to parse it and display the data that matches the guid using a database call with strongly typed values.
Example:
Guid value;
if (Guid.TryParse(Request.QueryString["ID"], out value))
{
SomeControl.Datasource = DatabaseCall(value);
SomeControl.Databind();
}
What this obviously means is that any user (provided they have the guid for the data) can technically access any other users data. Obviously predicting guids is next to an impossibility but I'm still uneasy about it.
How does everyone else deal with this problem? Is there a "correct" way? Is it even worth worrying about?
In various circumstances it absolutely is worth worrying about.
People tend to post or email URIs without stripping away the query strings
Most browsers store the whole uri including the query string in a history
Most browsers even offer autocomplete in the address bar which lets you try through already visited resources
The http request can be intercepted pretty much anywhere on its way from client to server, exposing the query string
I'd recommend some kind of user-based authentication mechanism like asp.net's membership provider.
In case you already are using some authentication, linking resource guids to their respective user ids in an association table might do the trick.
You answered your own question: "Obviously predicting guids is next to an impossibility"
However, the proper way to implement user access, is to build and manage an ACL. You can't simply rely on a unique string for that, because even if users don't guess the string, an attacker can still sniff the traffic and reuse the GUIDs they found.
I agree with #Laurent.
But - it depends on your type of business. For extreme security-related contexts such as banking, money transactions, sensitive personal data etc., I would go to an encrypted cookie, or simple - a unique key that is passed in the query string (as you asked about), but not a guid but something far longer (just make sure it's randomness is fairly hard to predict), along with a background task on the server that invalidates "tokens" that are older than X minutes, to mitigate the risk of stealing URLs.
Consider resorting to some standard mechanism such as ASP.NET Membership.
Note that when I say "client", I mean businesses or organizations that have signed up for the service.
I am creating a bug tracking application. I have decided to go with multi-tenant approach with respect to both the application instance and the database.
Hence, there is one huge bugs table with entries from all clients. The bug ID is an identity specification. Because of this, when any user under any client adds a bug, it gets incremented. For a client who has added just 3 tasks, the task IDs could be #45, #49, #53 because users from other clients may have added some in between!
Is this acceptable from a use-case point of view?
Sometimes clients may take the latest bug ID to be a rough measure of the number of bugs. But in fact it will be the TOTAL bugs in the system. Or they will be plain surprised if their first bug starts from #51134!
On the other hand, if I have this particular ID "behind the scenes", and calculate a "visible" ID for each client separately, they will see the numbers in order. But, when passing a reference bug ID as parameters in URLs I cannot use the user-visible ID because it is not unique. I don't think a ClientID - BugID combo will be elegant. I am afraid using the original identity specification value will cause confusion because the user will see one ID in the UI and another ID in the URL. And no need to say developers will try to use the URL by altering the ID and watch it fail.
How can I solve this issue? I do not want to go to a multi-database approach as I am kind of scared of the maintenance and upgrade process.
I think the principle of least surprise applies here: you need to be consistent with whatever you do. If you are unable to modify the URL scheme then that just leaves non-sequential ID's as the only viable solution. I don't personally see an issue with this, most bug trackers will be able to generate reports of how many bugs were reported in a given period, or how many on a specific project, etc.
On a slightly unrelated note, at work we use a single bug tracking system for all our projects. The system as a whole has a single incrementing ID for bugs in any project. We've never had an issue.
As a general rule of thumb don't show your surrogate keys (IDENTITY values) to your users if you can at all help it. Humans eventually want to change something that they know about so they need not know the primary key values...
The idea about generating a human-consumable identifier would solve your problem best, as you mention, just don't use it like a key in your system. Use your surrogate keys as the keys. (There are usually ways around passing keys in the url string...) Rather, treat your human consumable key as a display field after its initial generation.
Consider concatenating client name abbreviation or client company abbreviation or a portion of the date/time or other counter that you determine with a separate query against context (SELECT MAX(?) FROM q) or a combination these...
Good luck!
One special case I wanted to mention: if this is a public facing website, i.e. public support page or similar, where the customer gives you the support ticket number by phone (i.e. break of the communication medium) then it would be wise to construct an "intelligent" id. For example 5 numbers + checksum. Then the operator (or the system) can more easily check for misread ticket numbers.
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.
In the current project I'm working on, we are using the asp.NET profile to store information about users, such as their involvment in a mailing list.
Now, in order to get a list of all the users in the mailing list, I cannot simply do a database query, as the asp.NET profile table is, simply put, awful.
For those who do not know, the profile table has two main columns, the 'keys' column, and 'values' column, and they are organised as so:
Keys:
Key1:dataType:startIndex:endIndex:key2:dataType . . etc.
Values:
value1value2value3...
This is pretty much impossible to query using SQL, so the only option to find users that have a specific property is to load up a list of ALL the users and loop through it.
In a site with over 150k members, this is understandably very slow!
Are there specific reasons why the Profile was designed like this, or is it just a terrible way of doing dynamically-generated data?
I agree that it's a pretty bad way to store profile data, but I suspect the use case was just to get the profile data for a user with a single query but in such a way that it can be extended to handle any number of different profile properties. If you don't like it, you can always write your own, custom profile provider that separates each value out into its own column. Having implemented various membership and role providers, I don't think that this would be too complicated a task. The number of methods doesn't look too large.
The whole point of the Provider model is that it abstracts away the data source. The idea is that, as a developer, you don't need to know how the data is stored or in what format - you just have a common set of methods for accessing it. This means you can swap providers without changing a single line of code. It also means that you specifically do not try and access data direct from the data source (eg. going straight to the database) by bypassing the provider methods - that defeats the whole point.
The default ASP.NET profile provider is actually very powerful, as it can not only store simple value types (strings, ints etc.) but it can also store complex objects and entire collections in a single field. Try doing that in a relational database! However, the downside of this generic-ism is that it comes at a cost of efficiency. Which is why, if you have a specific need, then you are supposed to implement your own provider. For example, see SearchableSqlProfileProvider - The Searchable SQL Profile Provider.
Of course, your third option is to simple not use the profile provider - nobody is forcing you to! You could implement your own classes/database entirely, as you would have had to do in other frameworks.
I have implemented various custom providers (membership/Sitemap/Roles etc) and havent really looked at the ASP.NET Profile Provider after seeing that kind of thing (Name/Value pairs or XML data). I am not sure, but I think the Profile is primary created for User Preferences/Settings where the settings are only required for a specific user, I dont think the Profile is meant for User "Data" that can be queried?
Note: This is an assumtion based on what I think I know, please comment on this otherwise.