Using HttpCookie for timeout/ url expiration - c#

I'm working a web application, which is MVC 5 + Angular JS hybrid. There is no authentication in the web app and an anonymous user can come and ask for price for certain services. To get the price the user needs to answer some questions spread across few pages. Here is the flow of app.
User clicks button to get price
A unique URI the request is generated and user is redirect to the questions page
User answers questions and user submits the answers. The questions are spread across multiple pages navigated through angular routing. The answers are saved back to server on page navigation.
Once, the user submits the answers, the system (server) generate the price and display it to user.
Currently, if the user has bookmarked the URI, he can come back after days and continue from where he left. I want to prevent this behaviour.
What are the different options do I have in MVC? I can think of following:
Using HttpCookie with expiration time
Save the last access time in DB and validate if the user has come within a stipulated time frame?
I would like to avoid HttpSession. I'm inclined towards using HttpCookie since it looks to be the simplest option.
If we go with HttpCookie option, are there any side effect that I need to keep in mind?
Are there any other alternative within MVC I can look for?

If You want to expire some link without storage involved and your service need to be scaled I think You just need to add expiration date in your link and sign it.
I believe you can create your URL in a way like this
Pseudocode:
var info = [Payload any info you need to store(questionnaire id or so)] + [expirationDate]
var sign = HMAC256(info + [SERVER_SECRET])
var clientLinkParameter = info + sign
var clientLink = [baseURL] + [delimiter] + Base64(clientLinkParameter)
*HMAC256 - it's just example you can create signature using any algorithm you want
Now you can just check your link for expiration by parsing serialized data in the part before delimiter. You can also check that date was not modified by checking:
HMAC256([partBeforeDelimiter] + [SERVER_SECRET]) and [partAfterDelimiter] for equality. If they match this is the link your server sent (as only your servers know what the [SERVER_SECRET] is) otherwise it was modified by the client.
Now you can store any non secret data in user link allow user to share this link and other great things that you can do with a link without worrying that someone modify our link. Client can deserialize first part as well if its widely known serialization algorithm like JSON.
I think this flow will bring better user experience in case of suddenly closed browser (that will clean cookies in your case) and also sharing link with someone (if you need)
Hope this will help.

I finally, went with session-cookie. I hashed the unique id and saved it in the cookie with salt. I feel this is a reasonable approach for following reasons:
The anonymous user session is going to be short lived. Once, he closes the browser the cookie gets removed.
If the user bookmarks the URI, I look for session-cookie in the Http Request. If the session cookie is not found, I redirect the user to the challenge page.
I have gone for MD5 algorithm for hashing. I understand it is collision prone, but is faster than SHA. Since I do not store sensitive information like password in the cookie, I guess it should be fine.

I'd rather generate a token for a unique user session and store it on the server along with CreatedDate. So URL will have a token query string parameter that will be validated against the date.
It's more secure than relying on cookies
Allows for adding analytics to your site, where you start storing q/a combinations along with generated prices for a given user session. Start collecting data early. :)

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.

Force client to enter site from specific entry point in ASP

I wasn't really sure on how to form the search terms for this question but I didn't really find what I was looking for either way, so here goes:
How would I force a client to only enter certain parts of my website from certain entry points? For example I have an overview of what activities the company I work in currently got going but I only want users to be able to enter the page responsible for adding a new activity by pressing the "Add New Activity" button.
So that you can't enter that page just by typing in the URL for example. How would one achieve this in ASP?
The same way we do it in the real world, authentication, authorization. Whenever a visitor views a page on your website. They are sending a HTTP request, along with that request you'll receive any cookies that have been set by your web application on their computer on any previous visits, this happens on each and every request.
Authenticated users can be identified using cookies, usually what happens is... upon sign on, the server will set a cookie containing their identity. So when the authorized user requests to view "foo.com/topsecret" and the server receives that request, the server decrypts the data stored on the cookies and checks to see if its been tampered with... if all is good... access granted... if not... then it's simply denied.
In your case u can use the Session Variables and in login u can check all permission.
In your page you can add a check in Page_Load same this:
User myUser = (User)Session["User"];
string page = Path.GetFileName( Request.Url.AbsolutePath );
if(!myUser.pageSee.Contains(page)){
Response.Redirect("home.aspx");
}
you create a User class with proprerty a list of strings for the pages that you can view,
you may also add permissions for a single div.

Creating a secure temporary access token for user login, is this good enough?

Ok so I am creating an API for manipulating users and data in a web application using XML. If they POST XML they can create users, etc. I am using a 2-legged OAuth solution to secure and verify the API requests. However this question is not about that aspect of security, but the aspect I will describe is for allowing the user to login from an API request without having to type their username and password, here is what I have:
Step 1, partner uses XML API to create a user, if successful the system returns a path containing the new ID, "/user/99" for example.
Step 2, partner makes a request to user/login/99, this will create a new "Login Token" in my database, here are the relevant properties:
UserID int FK
AccountID int FK
Token string
Expiration date
Used bit
UserID and AccountID are related to the respective Users and Accounts table...
the Token is the first 20 characters of a randomly generated GUID with the dashes removed and all characters set ToUpper().
The Expiration is 30 seconds from DateTime.Now.
Used = false
Step 3, the partner will have knowledge of the URL of the system (which is on a different domain from the API), and they can now make a POST to it like this:
http://otherdomain.webapp.com/core/login/[insert guid here]
Now, the 'otherdomain' part is going to be unique per account, so at this point we verify:
Look up the LoginToken based on the provided guid, if it goes with the account that matches the subdomain, is NOT expired (within 30 seconds), AND 'Used' is set to false still, log the user in, set Used = true, direct them to the homepage or to another URL if one was provided via querystring.
So basically you NEED a complete registered App and secret key and all the jazz for OAuth simply to REQUEST the GUID which allows you to login but only works ONE time and within a 30 second window... and they need to have knowledge of the login URL in the first place, IS THIS GOOD ENOUGH?
In the end if someone can somehow know the GUID and the URL all within 30 seconds they could hi-jack the login, but what are the chances of that?
Alternatively, what could I add to make it more secure?
(Disclaimer: I am not a security expert.)
The immediate problem that I notice is this:
http://otherdomain.webapp.com/core/login/[insert guid here]
Based on your setup, the GUID token has to be given to the user when it's requested. That's effectively the password for the request. If you send it over HTTP, anybody who can snoop the connection has the token and it wouldn't be hard to hijack the session. This absolutely must use SSL for the entire process.
Beyond that, the problem is that you're sending the token to the user before they can use it, which isn't great. But with SSL it may very well be good enough for your purposes. I've used a similar method when dealing with a protocol that can't handle normal authentication, the user connects over the secured channel first and says "I want to do a transfer on the other one", and the server sends back a token they can use for that request. It works well enough on a low-security system. If you're protecting critical data, I'd strongly recommend you invest the money to bring in an expert to look at it before going to production.

authCookie and relogin the user

Scenario:
I have a tricky situation where need to keep many modules happy [Google Analytics, etc, etc...]. Got a asp.net page in the project which initiates the request on the third party website (after clicking the Process button) and redirects the user to the third party website. Transaction is processed on their website and then the control is returned back to the current page on our site. You can relate this scenario with kind of Paypal processing too, but it's not paypal.
Issue:
If the session is time out, I want the user to be again authenticated when the control reaches our website after the processing is done on the third party website. So I am thinking of passing the authCookie information to the third party website and then when the control reaches our website back, I will have the authCookie information (imagine it is the scenario) and then want to log the user back in. Can I do that by just creating an authCookie again based on the username?
It really depends on the transaction processing system you are using. If you check the result of the transaction by calling their API, then the response usually have a user id or something that you can tie to user id. You can store the user name in the cookie, cookies are per domain or subdomain and it won't get sent to the transaction processing web site if it is in the different domain than yours, which is most likely the case. Get or derive the user name from the transaction result response, compare it to the one you obtain from your cookie. If they match up, sign in the user. Signing the user in just based on the cookie contents is risky in many respects. First of all anyone can set the cookie with any name in it to the browser. Second, if you are signing in a user just based on a cookie, you'll basically get never expiring session. This is not what you want. For added security you can check the transaction time from the transaction result response and refuse to sign in if it was too long ago.
Oh, and in you question you mention that you "need need to keep many modules happy" but you do not expand on as to what you mean by this. So I'm just simply ignoring this bit. Not sure what a happy module look like =)

Categories

Resources