Is Forms Authentication as described in the Nancy docs susceptible to session hijacking? - c#

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.

Related

C# and ASP.NET Core 6 : authentication and user details in "session"

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

ASP.NET Core. How can I invalidate JWT-Token after password change

Sorry for my bad English. I'm writing an application in ASP.NET Core using Vue.JS for client-side. For authenticate user I'm using JWT and ASP.NET Identity. I have a method for change the password. But I can't understand: How to invalide token after password change? I want that the user authenticated in another browser will logout after that. Is there a man who haved a problem like this?
You normally don't invalidate JWT's because they are meant to be short-lived access tokens and therefore after the password change, request for new token will prompt the user to reenter credentials.
If you do absolutely need to invalidate the JWT immediatelly after password change - you need to look into Introspection where your backend api essentially has a backchannel to your token issuer and it can then re-validate token every request. This way if you invalidate token at the issuer side - it will reflect on the api side immediately.
I've been thinking about this and the inability to invalidate a JWT that's already out there may not be built into anything, but is possible.
Here's the narrative: You have an alarm system installed that can be controlled via web and your ex-S/O is logged in to your previously shared account. They are upset and they keep enabling the alarm at random times.
If the web app uses JWTs to store session, you could change your password but the JWT your ex possesses will still be usable for a period of time until the timeout is reached.
Solution 1: short timeout. but what if you want to stay logged in for longer periods (such as a password manager)
Solution 2: logout ALL users by changing the Signing Key of your Certified Authority, basically invalidating ALL JWTs across the board. This is still a less ideal route as I'm sure you can imagine.
Solution 3: track the current JWT for each user in your Users table. If the JWT they possess is different from the current one, then they aren't authenticated. If the user logs out, nullify the stored JWT-data in your Users table which would equally unauthenticate JWTs for that user and force a relogin.
I'd also recommend storing a bool of "logged in" for the user. DO NOT RELY ON THIS. This would be a value to set to true when they log in, set it to false when they log out, and validate the value is 'true' if they ever pass you a JWT. This will ensure that the moment they logout they are forced to reauthenticate.
Assuming you go with solution 3:
When storing JWT data for this solution, I'm leaning towards not storing the entire JWT because it's rather large text to begin with. Alternatively just store the JWS (JWT Signature) which will make the stored value both smaller and unusable if captured for any reason.
Next, it's a hash to begin with so we could just store the last maybe 9 values (9 because int32 max is 2147483647). We just need a bit of uniqueness, not much.
Next, we could avoid the string comparison for validating that the JWS passed is the active one if we use regex to pull the integers out of the JWS and again take maybe the first 9 numbers you encounter.
Following this method, and returning to the narrative, if you were to log out your user would be marked as logged out resulting in both yourself and your S/O being required to reauthenticate. (assuming you've changed your password you're golden, otherwise it's time to contact Customer Support)
If you were to log back in, you'd get a fresh JWT and a new signature would be stored in the Users table. If your S/O were to try to use the site, they would not be authenticated with the their old JWT and would be forced to sign back in.
Trade-off: If we only store the JWS, or a part of it as I suggested, multiple users can't be signed in to the same account at once. How you feel should feel about that really depends on your app.

Form authentication cookie vulnerability

I have a question regarding Form authentication cookie vulnerability. In JavaScript we can use document.cookie to access form authentication cookie value (assuming it is not httponly). This value is encrypted. I have read in many blogs that if someone get's this value our security is breached. My question is how can he(attacker) breach it(the credentials inside the cookie) since the form authentication encryption method uses machine key to encrypt that cookie, so to decrypt it, the same machine key would be needed? Isn't that so? Can you clarify me on this that how that cookie value is vulnerable since the attacker should have my machine key with him only then he can decrypts it? Am I right here?
how can he(attacker) breach it(the credentials inside the cookie) since the form authentication encryption
He doesn't have to decrypt the encrypted cookie. He could just use the encrypted value of the cookie and become you.
The server does the encryption, so it doesn't know that the browser giving it the cookie was who the cookie was originally issued to.
Using an extension like Modify This Cookie (or anything else that achieves that functionality) would allow me to set my cookie to your encrypted value if I were able to obtain it.
Ironically, the very same question was asked about StackOverflow. Have a look at Troy's post for further information.
What I've done, don't know how much it actually helps, but I've never seen any breaches (although there are some 100 attempts made) is to pair the cookie with an IP-address, which means that I look up if the call comes from the same IP-address as the previous call, if not, it resets the cookie and you'll have to log in again. This isn't exactly viable for all sites, but in my case it was more important to add some measures of security rather than allowing for mobility.
This approach is probably nicely suceptible for MITM attacks, but you can never protect yourself against all eventualities except if you have a monster budget and no restrictions regarding performance and accessibility.

Cookie safety issues

How can I remember a user that is logged in without having a security issue? Currently, I am storing the id and a guid into two different cookies and compare them when there is no session alive. If it match then I re-create the session. Btw, both id and guid are nore encrypted.
Is this method safe enough, or should I follow a rather distinct way?
Since cookies can be easily stolen by use of XSS, does not matter if you place information in just one cookie or two, because a theft will take them all.
I have solved with a more complex procedure: I place one encrypted cookie divided in 2 parts (but 2 cookies will work as well), one fixed and the other variable each session. Both are saved also on server side to check: they are only session identifiers, no sensible information contained in the cookie, the correspondence with the user id is saved on the server.
If a fake user enters the account with a stolen cookie, the variable part (or cookie) will change, so when real user connects again he will not be able to enter and you will have the proof that an unauthorized access occurred: then you can delete the permanent session on server side (defined by the fixed part or cookie) in order to avoid any further access by the theft. The real user will re-login and create a new permanent session with a new cookie. You can also warn him that you saw a security flaw, suggesting him to reset password (operation that should never be accessible directly from cookie) or to use another browser for unsafe navigation.
If you save additional user information (user-agent, IP by location) you can check cookie validity also on them in order to avoid even the first entrance of the fake user.
I would recommend you using forms authentication for tracking logged in users in an ASP.NET application.

mvc custom httpcookie used to authorize

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.

Categories

Resources