Currently, I'm using the FOrmsAuthentication.SetAuthCookie to store an Id so I can use it on the next page that is "Authorized" (using custom authorizeattribute controller). But I'm currently thinking of making a custom cookie using httpcookie so I can store more data, or easily maintainable data. Was wondering if having the kind of cookie will I be able to authorize the current user to access the "Authorized" controllers? If so how do I go about it.
Hope that made sense.
Please let me know your thoughts.
Just put your extra stuff in a different cookie. And if forms auth says the user isn't authenticated, don't read the other cookies. No need to overload the purpose of the auth cookie (and non trivial to do so securely)
There is a UserData property of the FormsAuthenticationTicket. It is a string so you will have to be able to serialize/deserialize any complex data.
Good security design says dont store this information in a cookie - figure out another way (server side). Recently (octoberish) the ASP.Net POET vulnerability taught us that forms auth tickets could be forged because the machinekey could be determined and hence data encrypted as it would be on the server. I know - not exactly what you asked but I think it's important to not store sensitive data on the client side.
Related
I'm going to get so many "okay grandpa" comments for this one.
I've read a dozen articles and every SO question I could find on this subject.
I must have been away too long or missed something completely, because I swear that user authentication used to be very simple. I seem to recall built-in methods and a session on the server simply knowing who the user was via a cookie or similar, with the ability to store information "in session". I don't recall even setting up authentication in years past, it was just built-in to new applications.
Instead, the most succinct guide I could find is very involved. I think I need a token authorization/authentication setup because there may be consumers (like apps) who don't have a typical cookie pattern these days. In my head, the token works like a cookie except it's manually held on the user end and passed via header with each request?
To its credit, the guide worked, at least for logging in and correctly utilizing the simple Authorize attribute in controllers. However, User.Identity.Name is always empty, even when User.Identity.IsAuthenticated is true, which is perplexing.
How I think auth is working:
User request hits API with username/password
Service checks the combination, and returns an encrypted JWT to the user
The user sends the JWT back with every request
The server decrypts this JWT to identify the user - this is probably where I'm wrong
So here is where my question comes in:
I need more data about the user, like access to the entire UserModel with every request, but I don't want to go to the database to find it every time. This is where I think there should just be a session object in memory, but that doesn't appear to be the case with token authentication.
TL;DR:
Where do I put user-specific, short-term ("session") information for consumption in future requests where a user is identified with a JWT in the Authorization header instead of a cookie?
Session state isn't right, because it's hard-wired to a cookie
HttpContext.Items aren't right, because it's just for the one request
Cache storage isn't right, because it's not user/session specific. I could potentially create a session-like user-keyed storage here but that seems way, way over-engineered for this.
Basically anything where I'm passing all the data (not just a user identifier) to the client then relying on the client to pass it back seems wrong? But feel free to correct me.
The server decrypts this JWT to identify the user This is probably
where I'm wrong
The JWT token is not encrypted, its signed so you can't alter it. You can open it if you look at jwt.io for example.
Where do I put user-specific, short-term ("session") information for
consumption in future requests where a user is identified with a JWT
in the Authorization header instead of a cookie?
You put it in the principle claims of the token. In the guide you linked it wrote:
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.NameId, user.UserName)
};
So you add whatever you want to the claims to store it on the token and later you can access this data via:
var claim = _contextAccessor.HttpContext.User?.Claims.FirstOrDefault(d =>
d.Type == ClaimTypes.NameIdentifier);
You also can't use any of these other examples that you listed like HttpContext.Items because those are not signed. If the token is altered in any way the system identifies this and returns a 401
A common use case for WebAPI would be to have shell views rendered by MVC controllers, which contain javascript that then hit your API to access data.
But let's say you have some expensive API operations and you don't want people remotely accessing those endpoints -- you only want your MVC views, delivered by your application, to access them. How could you go about protecting them?
In this case Request.IsLocal doesn't work, because javascript is invoking it from the client's browser on their machine. Even if it did work, you need to dig to get the real HttpContext in order to find this property -- and that solution wouldn't work in self-hosted WebAPI.
For API endpoints that require a valid IPrincipal, you could protect them with the [Authorize] attribute. But what about API endpoints that you want your app to be able to access for anonymous users?
I have tried a solution and will post it separately as an answer, because I'm not sure if it's the best (or even a good) approach.
If your MVC site uses authentication, you could enable forms authentication for your Web API methods. You could write a custom [Authorize] attribute that will check for the presence of a forms authentication cookie which will be sent from the AJAX call and if present construct the principal.
Another possible solution is to protect your API with tokens which is a more RESTful style. The idea here is that when a user authenticates on your MVC website you could generate and pass a token to the view which will be used when sending the AJAX request to the Web API which in turn will verify the validity of the token and its signature.
If on the other hand your site doesn't use authentication, then things will get very complicated because you have no way of knowing whether the request comes from a trusted client since you are using javascript to call your API methods.
Before you go harping about "what have you tried", here is what I have tried. It works. Just not sure if there is a better way.
Create an MVC action filter and add it as a global filter during Application_Start.
Create an Http (WebAPI) action filter and use it on actions that should reject remote requests.
The global MVC filter does this:
Looks for a specific cookie in the request. If the cookie is there, its value is decrypted. The decrypted value should be a string representation of a DateTime, so use DateTime.TryParse to get it out. If the value is correctly parsed to a DateTime, and that DateTime is less than a day old, STOP HERE and do nothing else.
If the cookie is not there, or cannot be decrypted / parsed, or is older than a day, write a new cookie to the browser. Use the current DateTime.UtcNow.ToString() as the value, encrypt it, and write it with HttpOnly = false.
The WebAPI filter does this:
Looks for a specific cookie in the request. If the cookie is there, decrypt its value and try to parse it out as a DateTime.
If the value is a valid DateTime and is less than 2 days old, STOP HERE and do nothing else.
Otherwise, throw a 403 Forbidden exception.
A couple of notes about my current implementation of this. First of all, I use AES encryption with a shared secret and a salt. The shared secret is stored as an appSetting in web.config. For the salt, I enabled anonymous identification and used Request.AnonymousID as the salt. I'm not entirely fond of the salt because it's tricker to get at in a WebAPI controller, but not impossible as long as it is not self-hosted.
I read the documentation of Nancy Forms Authentication. As far as I can tell, the approach recommended there leads to lifelong session IDs:
"The identifier is the token that will be put in the authentication
cookie which will be used to re-establish the identity of the user
that is performing the request, so that you do not need to enter your
credentials for each request."
As far as I understand, that "identifier" is what most people call a session ID.
It is also important to know that the identifier should be treated as
permanent for the user that it was generated for and will be reused
across requests and application sessions.
Is this really the recommended approach? If I understand correctly, this means that session IDs never change and never expire. So the session ID is the equivalent of a password, which
is retransmitted in a cookie with every request
is probably stored in clear-text in the DB, if you follow the docs to the end
I know that I could implement this differently with Nancy, but my point is that such an approach should not be explained in the docs as reference.
So if an attacker ever succeeds in stealing that session ID, e.g. by an XSS attack, he gains lifelong access to the system.
Please correct me and show me the mistake in my thoughts!
The identifier you are referring to isn't a session id, it's an unpredictable user identifier, which is then mapped (if necessary) to the real user identifier in the back end. This is so if someone logs in as user X, and somehow manages to decrypt, re-encrypt and re-sign the cookie they can't just change the user ID to "admin" or something similar and gain admin access (which is how the ASP.Net Oracle attack worked). It's also HttpOnly, so not really capturable via XSS, although technically it could be captured using XST.
Creating and expiring a session (and deleting the auth cookie if necessary) is a different task altogether - how and when you determine if an auth cookie should be accepted, removed, or confirmed with an additional password request is application specific. This is a common pattern now where a site will consider you "logged in" eternally, until you do something "secure", in which case it will ask you to revalidate if you haven't done so recently.
Hope that makes sense.
that "identifier" is what most people call a session ID.
It's not. It's something like UserId. as the documentation states:
We have chosen to use a GUID as the identifier. The reason for this is that using something like the username of id is a potential vulnerability, because, if the cookie encryption was somehow compromised, it would be easy to spoof the identity of another user by guessing their username or id.
They're just using a GUID assigned to the user for more security. Of course, (cookie based) FormsAuthentication has all the disadvantages of cookies. If someone can get access to your auth cookie, they can authenticate themselves as you. But session cookies and forms authentication cookies are completely different things, This answer states the differences pretty clearly.
I am planing to implement a mult- tenant MVC application, where each tenant gets a "sub site" URL, so that rooting would look like:
www.mysite.com/{TenantId}/{Controller}/{Action}
When a user logs into the application, the login shall always be associated with a single tenant (there is no need for single sign on). However, it should be possible that he registers with two or more tenants in the same application. In such case, I need him to be able to simultaneously use both "sub sites".
As I understand it, the FormsAuthentication is using one cookie with a name specified in the web.config, visible in the code through FormsAuthentication.FormsCookieName.
I was thinking about imlementing an approach similar to this one: implement custom cookie creation and checking (using FormsAuthentication.Encrypt\Decrypt for creating the tickets and then manually creating cookies with different names for different tenants). In this way the user could have several cookies, one for each tenant "subsite".
I am wondering, if this approach seems sensible/secure? I was dotPeeking the FormsAuthentication stuff and there is quite some additional stuff under the hood - with a reason I suppose. Also reading articles like this (where the cookie expiration in the secure connection scenario was not handeled properly) makes one wonder, if custom security implementation is really the best way to go...
Alternative to several cookies might also be setting the cookie Path property. If I understand it correctly, the cookie shall be sent only with requests starting with {TenantId} if I set its path when creating it? Will FormsAuthentication know how to handle such cookies? When new ticket will be reissued, will the Path be respected?
And of course, all other suggestions are appreciated as well.
I'm now building a App that use asp.net webAPI on the server side,I got a problem about the validation:
I want to provide my webAPI for multi-platform,just like browser's javascript,or windows phone ,and so on,so I decide to implicit the validation with HTTP-BASIC,"(forgive my poor English),the problem is ,In the past time.
I always take some User's Information in SESSION,but we know that webAPI with RESTful-style is Session-stateless,so how to store the User's information:
And I get some idea,I hope you can help me to make the right choice,thx a lot
1.
put the information into the browser's cookie except the user's password and other important infos. everytime I make the http-request ,i take the cookies.and on the server-side,I can query the user's infomation.and make other steps.(the sequence will not work on moblie platform,cuz cookies only in browsers)
2.user HTTP-BASIC validation,and everytime the server get the httpRequest,it get the username and password in the HTTP-Headers,and server-side also can query the user's information.
Most REST APIs I've seen handle authentication one of two ways:
HTTP Headers, be it basic auth, or some custom headers to pass credentials. This would be your option 2. This is only really good if you're running over HTTPS, since the credentials will be in clear text in the headers.
Using a pair of tokens, one as an identifier (somewhat like a user name) and one shared secret between the client and the server (somewhat like a password). A hash is then made of the identifier, parts of the request parameters, and the secret. This hash and the identifier is then sent along with the request. The server, knowing the secret, then computes the hash using the same method, and ensures they match (Amazon Web Services uses this method, along with anything using OAuth).
More web APIs seem to be migrating to the second method here, as it is resistant to tampering and replay attacks, unlike basic auth. It is, of course, more complex.
RFC 5849 Section 3.4 for OAuth, while dry reading, goes through the process used for creating the hash, and probably would be a good starting point for implementing, if you desire. A basic implementation in C# is provided on the OAuth Google Code site, and might be a better choice to start with.