I'm developing a web app and I'm wondering if exposing UserIds to the clients is potentially posing a security vulnerability. (By UserId I refer to the Id of an Identity user object created by the Identity Framework and used as a PK of the users table.)
To give some context or an example: in my app, I need to distinguish between content that is posted by the signed in user and the content that was posted by others. In a naive approach, I would just compare the UserId of the content to the UserId of the currently authenticated user. But that would mean that the client sees the Ids of all involved users.
My gut feeling tells me that this is not a good idea but I couldn't pinpoint to why. So, I wonder if there's a guideline around this question. Maybe it's just the general rule to reduce the surface of knowledge that is exposed to a minimum.
If this is the case, how should I proceed? Would hashing of the UserId help to solve the problem or are there better approaches around?
EDIT
The example I made is not the best because this problem can easily be solved on the back-end by comparing user IDs there and then sending the contents to the client already tagged as "mine" or "by others". But still, the general question remains.
If user IDs are themselves sensitive data,for example, your primary keys for some reason happen to be social security numbers, that'll definitely be a security and privacy liability. If your user IDs are just auto-increment numbers though, it should be fine.
It is always best to expose a unique identifier other than the primary key outside your system. It gives you more flexibility in resolving data mix-ups, dealing with data migration issues, and in otherwise future-proofing your system.
If UIDs are just identifiers for users. Knowing a user's UID does not grant you any permissions that are associated with that user. Sharing the UID in URLs is about as safe as sharing your username on Github, or your unique ID on Stack Overflow.
Stack Overflow displays user IDs in their URLs in order to make user profile lookups work: https://stackoverflow.com/users/10158551/xing-zou
Anyway, it is up to your design and you need to consider more than we could.
Refer to Should I expose a user ID to public?
I would put this in the low risk category. Exposing user ids does increase the risk surface as you have correctly identified.
For you application, it sounds like you require an identifier for the post and an indication of whether that post has been made by the user or by someone else.
You could structure that in the following way to avoid the low risk exposure:
GET /posts
{
"postId": "AJDIWC",
"isAuthor": true,
"content": "This is a post by the user."
},
{
"postId": "LISHWE",
"isAuthor": false,
"content": "This is a post by another user."
}
EDIT
To answer your question following the edit, yes, it is best practice to avoid exposing identifiers from other users unless the authorisation boundary allows it.
For example, there is no issue having an admin user of an RBAC protected application see the unique identifiers of users within their security boundary.
It's usually not a good idea to expose the user id at the client-side. If you need any information, username or a unique number is better than the exact user id in the database. This is generally not an issue if your application has protections against SQL injection attacks. But in case there is any vulnerability in loopholes, if anyone knows the user id for a user, they can inject SQL scripts for that user.
A better idea is to issue an access token to your clients with claims inside that. The access token will perform authentication for you on the server-side.
Related
I am currently in the process of sketching-out an application that allows real-time interactions with website visitors.
Therefore, I have two different "User-types":
Unregistered User: these are the visitors
Registered User: these have a (custom) ASP.NET MVC membership
Now, I am persisting "UserNames" and ConnectionIds in a DB so I can freely scale at some point in the future. I do this by accessing Context.Identiy.User.UserName from within the Hub and then query the DB for any existing "sessions".
Here is the problem:
I need two different types of "User"
For one, I want to dynamically generate a GUID - these are the visitors and will be removed from the database after a given amount of inactivity.
These are the admins, they have their proper identities attached to the Context object.
So, how would one go about accessing a "session" from SignalR? It is not really a Session, I just need to get a SessionId from a Cookie on each initial request to the MVC-Controller, that's all. All I need to be able to do is:
Have an auto-generated "SessionId" which I can use to persist visitors across requests
Have a more "extended" identity: I want to use UserId instead of UserName
Anyway, I hope this makes sense but chip in if anything is unclear.
Okay, I just realised that I can use "HttpContext.Current.Request.AnonymousId" and I am linking this up to a Session-database.
Here some relevant documentation: http://msdn.microsoft.com/en-us/library/system.web.httprequest.anonymousid.aspx
This solved my problem in this case. :-)
I am after some advice regarding use of GUIDs from the security perspective. I have developed an ASP.Net application. It provides the user with access to some material, such as documents and photos, that aren't on the web server. These are stored on a file server. I have a 'GetResource.aspx' page which takes the ID of the resource, opens it using System.IO.FileInfo writes it to the response stream and returns it.
So, GetResource.aspx?id=123 would return, say, a picture that the user has access to. Of course, the user could manually enter the URL as GetResource.aspx?id=456 in which case the picture / document etc with that ID would be returned and it may not be one they have permission to access.
So clearly using an integer ID is not adequate. Would using a GUID as the ID provide enough 'randomness' that I could reliably assume the user could never manually enter "GetResource.aspx?guid={A guessed guid}" and ever expect to access a valid resource, including if using a script that made many random guesses per second?
Or, is there no substitute to determining the ID of the user from a Session variable, determining he does actually have access to the requested resource and only then returning it (Which as I write this I'm more and more convinced is the case!).
Thanks
There is certainly no substitute to authenticating the user and seeing if they are authorized to access the resource. What you are proposing here is a method of making it harder for a user to hit on a valid id for a document they are not authorized to view (either by mistake or on purpose).
A GUID is certainly large enough that you would never get "accidental" valid ids in practice. That makes a GUID without authorization checks a system that works great as long as noone is actively trying to break it. On the other hand, authorization checking is a system that would work great even in the presence of active attackers (of course this depends on what the attackers can manage to do).
You should choose between the two approaches depending on the nature of your application (is it public? are the users known and accountable for their actions? how bad would a "security breach" be?).
You should be determining if the user is authorised before blindly serving it if it is protected content.
The GUID does help to some extent, it makes guessing URLs harder, so I'd still recommend using them. But URLs can still be shared (even accidentally). If you are just going to serve up the content anyway regardless of who makes the request then it is of little real protection.
If you think that content is restricted one and having some personal data then you should go with username and password thing.
If encrypted data is stored on a server, and decryption key is disseminated to the legitimate users (through email), is there a need to implement access control policies?
What could be a possible scenario where I need both of them (if decryption key is only available to the legitimate users)?
Access control and authentication are two separate modes of security. Depending on your needs, you may need one or both.
Encrypting data on the server, and then disseminating the key, is arguably a form of authentication, since (at least in theory) knowing the key proves that you are a legitimate user.
Access control would be more along the lines of giving different levels of access to different users -- for instance, access to general documents for most users with a key and access to privileged data for a select few users.
Ultimately, you have to evaluate your needs and decide on which modes you require.
It depends on your security needs. Do you have any need to have levels of security?
If you just need to ensure that only legitimate users can access your site then you can just encrypt their username with the key, then have them use a password, so that they have to know something and they have something (two-factor authentication) and they can get into the site.
A term that applies here is the Princple of Least Privilege
An enterprise system will have a number of different roles that users or applications perform. In these cases, it's appropriate to stop actors in one role accidentally (or deliberately) intruding into the realm of another actor's role.
A simple analogy: I am an employee of a company. I am legitimate member of the company with a pass card who can get past the security desk to reach my workstation. However, I cannot access the company's bank account.
The vast majority of employees, even if they were given the bank account details, would do nothing inappropriate with the information. As the manager of this company, you could either trust the honesty of each and every employee, or you can go the far simpler route of recognising they have no need to access the account and keep them locked out. Then, if money starts disappearing, you have far fewer people to be suspicious of.
Audit and revocation.
Audit because you want to know if someone accessed data, not if they could do it because they had a key ( this is usually a requirement for say HIPPA/HITECH)
Revocation because re-distributing keys for the data may be impractical and depending on the underlying crypto scheme, revocation may be impossible.
Access control policies, surprisingly, flow directly from your needs to control access.
When one of legitimate user accounts becomes illegitimate for any number of reasons (user changed employment, violated terms of service, reported identity theft), then you have to control access to that account's data somehow.
Sites like ebay and amazon.com Know who you are with a message like
Hello, Bob. Please log in.
... but they also know you haven't authenticated yet for this session. What is the best way to implement this in an ASP.NET application using the Membership API/Framework? I can think of a few ways to go here, but my primary concern is to not compromise security in the name of convenience or apparent cleverness.
Special bonus question: is there a commonly used term that describes this session state (e.g., identified but not authenticated)
They do this with a cookie. No private information is needed other than the first name, or a unique identifier for a database lookup.
I think "identified but not authenticated" says it all...
I suspect the way most sites do it is with a cookie storing your "Name" and then they read and display this information on the page
Encouraged by SO, I'm trying to write an ASP.NET site that uses OpenID for user authentication. It's a regular WinForms site (not MVC.NET), using the DotNetOpenId library for authentication.
Is it safe for me to permit/deny administrative functions on the site by simply comparing the current session's "ClaimedID" (as returned in the OpenIdLogin_LoggedIn event, as member DotNetOpenId.RelyingParty,OpenIdEventArgs.Response.ClaimedIdentifier) to a known administrator's OpenID (i.e. mine)?
If so, is it safe for this ID to be visible (e.g. in open source code), or should it be "hidden" in a configuration file or a database row? (I know it's better design to make it configurable, my question is just about safety.)
My solution is to follow the same idea of the Roles table. After you've authenticated the user, look up that user's roles. If the user has role "Administrator" in the UserRoles table, then they can do whatever the Administrator can do.
I don't broadcast open ID's in my app. They're stored in the table. On every action result, I'm hitting the Users table, since I have also modified mine to store various user state information. With the exception of the home page, there is going to be some user information that I need from that table. I'm using LINQ, so I include the .LoadWith() to load the User with his list of roles when it serializes.
Jarrett makes some good comments about using database tables.
Just to answer another one of your questions, no, it's not a confidentiality thing to put your OpenID in your code generally. If setting up roles seems overkill for your site, a simple equality check against your ClaimedIdentifier is just perfect.