I'm writing a GWT application, and I've been asked to implement the user management portion of the website. I know a little bit about salting, hashing, encrypting, and user tokens, but I've never read any books or studied papers on the subject.
I'm planning on doing a stateless implementation which means keeping user identifiers and submitting them to the server on every request. No server-side session data will be used. I'm looking at Apache Shiro, and I like the low level of integration so that I don't need to hook up to complex frameworks.
My biggest concern is with having a user token that doesn't expire. If I give them a token and they never log off, then I want the token to persist and be valid so that they can leave the web browser open overnight, and not have any session problems.
Does this plan leave the site vulnerable?
There is always some state that you'll have to keep on the servers if you want to perform any kind of user login. The only question is: Where does that state reside?
In the application server or
In the database (or maybe some other storage)
Obviously, the user name and password will be saved in the database. A session token is usually kept in the application server's memory - but it doesn't have to be. You could just as well save it in the database.
Because your implementation is stateless, with your current solution you'll have to retrieve the user name and password from the database for every request. You could easily change this to retrieve a token and timestamp instead. The only significant change is, that there may be multiple sessions per user, so you'll need a 1:N relation for users/tokens.
First:
If you want to write secure web pages read the OWASP Top Ten. This is comprehensive summary of most web applications vulnerabilities.
Second:
The main problem with your solution is the expiriation time of that token. If attacker will find out its value he will be able to impersonate real user for a long time. Also it is vulnerable for a brute force attack, when attacker will try to guess a token value. It would be wise to ask the real user for a password once in a few days and then change the token value.
I'm planning on doing a stateless
implementation which means keeping
user identifiers and submitting them
to the server on every request. No
server-side session data will be used.
I'm looking at Apache Shiro, and I
like the low level of integration so
that I don't need to hook up to
complex frameworks.
What happens when I copy someone's cookie?
What happens when I decipher the identifier and change it? (is it a int value?)
Related
For authentication in my REST API, I am using JWTs, which only contain the client user's UUID.
To check if the user is not blocked or has rights to execute a specific endpoint, I fetch the user's data from a PostgreSQL database using the UUID of the JWT, and verify if the user is allowed to execute.
Is it a good practice to do a database operation for securing every API call?
Also thought about storing roles and rights in the JWTs but what if these roles and rights change in the database and the JWTs data becomes stale? Is there any solution to the stale data?
You have to check some data store for staleness with JWT.
If you conclude with performance tests and measurements that accessing a PostgreSQL DB for every request would be too slow, then you optimize that part. Maybe optimize your DB performance by changing the data structure or configuration. Or use a completely different database just for this purpose. Bad practice would be trying to optimize this prematurely.
Here's an article that talks about how to manually expire JWTs, it describes an example with using Redis:
An implementation would probably be, to store a so-called “blacklist” of all the tokens that are valid no more and have not expired yet. You can use a DB that has TTL option on documents which would be set to the amount of time left until the token is expired. Redis is a good option for this, that will allow fast in memory access to the list. Then, in a middleware of some kind that runs on every authorized request, you should check if provided token is in The Blacklist.
TL DR: No its not :-)
In general JWT's are not the most suitable solution for scenario you describe, you are already facing the first trouble of it now.
Because you better store stateless information in your JWT, otherwise you would be better of using other authentication solutions.
Conclusion
Stateless JWT tokens cannot be invalidated or updated, and will introduce either size issues or security issues depending on where you store them. Stateful JWT tokens are functionally the same as session cookies, but without the battle-tested and well-reviewed implementations or client support.
Unless you work on a Reddit-scale application, there's no reason to be using JWT tokens as a session mechanism. Just use sessions.
source: http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
And some other related posts:
http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/
https://medium.com/#yuliaoletskaya/can-jwt-be-used-for-sessions-4164d124fe23
https://logrocket.com/blog/jwt-authentication-best-practices/
Most security consultants / auditors I spoke to also are very strong in there statements about JWT, they are widely overused and have a specific problem domain.
But if you really want/need to, I would follow #ekuusela's answer, especially given:
Bad practice would be trying to optimize this prematurely.
Hello fellow developers
I have obviously under estimated a thing when developing my first complex web site, where user creation and login is required.
It appears that cookies can be edited and modified by the user logged in, by using some developer tools i.e. in Google Chrome. That, I never gave a thought.
So, here is my issue.
When the user is logged in, I store the user name in a cookie.
If username-cookie is not blank, and I can find a user file with that name, the user is logged in, per se. Otherwise, no user is logged in.
When the user logs out, I simply expires the cookie, which works fine.
Now, the problem is, that a user obviously can edit the content of a cookie, outside the web application, or with javascript.
What would be the correct approach here to ensure, that the username cookie is not compromised in any way, other by my web application?
Making them read-only is not possible, I assume. Encrypting the cookie and then decrypting might work, I guess. Then, the cookie would be nonsense to the user, and if modified, result in a logout, as no valid username can be found upon decrypting the edited cookie.
I have stalked Googles cookies, and it appears that there are a lot of xxID cookies, which contains garbage. Does that mean, that encrypting/decrypting is the only way to make it work? I also considered some kind of login-ticket, but that would require a table lookup every time a user interacts with my web page.
Can anyone give me a hint as to what would be the correct approach?
Thanks in advance
Best regards,
Karsten Heitmann
You should look up session management for the language you are using.
The traditional approach is that when a user logs on, your application generates a long, cryptographically random token called the "session id" and sets that into a cookie. It stores data like who is logged in on the server side identified by the random value, so when a logged on user comes back, the browser sends the cookie with the random session id and the application can look up session data on the server side. This way an attacker has no way to guess a valid session id for a logged on user, assuming the session id is cryptographically random and long enough (which more precisely means it has enough entropy). Logging out means deleting the session data on the server side, and also removing the cookie, but that is not the most important part - the session will be invalid anyway.
Note that you should not code this yourself. You did not mention the language and environment you are developing in, but session management is rather tricky business if you want to secure it, and it is already provided by most languages / frameworks.
Just for curiosity, the encryption approach you mention is by the way a valid one. Some frameworks actually do that, but you should not attempt to code that either, because it is very easy to get it wrong, lots of things need to be taken care of to make it secure enough. Unfortunately an answer here is not the right format to go into details I'm afraid.
Btw you mention looking at Google. They use their own single sign-on solution, it is very complex compared to simple session management, so it's probably not the best example for you to look at. Find simple websites, most of those work the traditional way.
UPDATE: I have concluded my research on this problem and posted a lengthy blog entry explaining my findings: The Unspoken Vulnerability of JWTs. I explain how the big push to use JWTs for local authentication is leaving out one crucial detail: that the signing key must be protected. I also explain that unless you're willing to go to great lengths to protect the keys, you're better off either delegating authentication via Oauth or using traditional session IDs.
I have seen much discussion of the security of JSON Web Tokens -- replay, revocation, data transparency, token-specified alg, token encryption, XSS, CSRF -- but I've not seen any assessment of the risk imposed by relying on a signing key.
If someone breaches a server and acquires a JWT signing key, it seems to me that this person could thereafter use the key to forge unexpired JWTs and secretly gain access. Of course, a server could look up each JWT on each request to confirm its validity, but servers use JWTs exactly so they don't have to do this. The server could confirm the IP address, but that also involves a lookup if the JWT is not to be trusted, and apparently doing this precludes reliable mobile access anyway.
Contrast this with a breach of a server based on session IDs. If this server is hashing passwords, the attacker would have to snag and use a session ID separately for each user before it expires. If the server were only storing hashes of the session IDs, the attacker would have to write to the server to ensure access. Regardless, it seems that the attacker is less advantaged.
I have found one architecture that uses JWTs without this disadvantage. A reverse proxy sits between untrusted clients externally and a backend collection of microservices internally, described here by Nordic APIs. A client acquires an opaque token from an authorization server and uses that token to communicate with the server app for all requests. For each request, the proxy translates the opaque token into a JWT and caches their association. The external world never provides JWTs, limiting the damage wrought by stealing keys (because the proxy goes to the authentication server to confirm the opaque tokens). However, this approach requires dereferencing each client token just as session IDs require per-request dereferencing, eliminating the benefit of JWTs for client requests. In this case, JWTs just allow services to pass user data among themselves without having to fully trust one another -- but I'm still trying to understand the value of the approach.
My concern appears to apply only to the use of JWTs as authentication tokens by untrusted clients. Yet JWTs are used by a number of high-profile APIs, including Google APIs. What am I missing? Maybe server breaches are rarely read-only? Are there ways to mitigate the risk?
I believe you're thinking about this the wrong way. Don't get me wrong, it's great you're considering security, however the way you're approaching it in regards to double checking things server-side, adding additional checks that defeat the objective of stateless sessions, etc, appear to be along a one way street towards the end of your own sanity.
To sum up the two standard approaches:
JWTs are sessionless state objects, MAC'd by a secret key held server side.
Traditional Session Identifiers are stored either in memory or in a database server-side, and as you say are often hashed to prevent sessions from being hijacked should this data be leaked.
You are also right that write access is often harder for an attacker to achieve. The reason is that database data is often extracted from a target system via a SQL injection exploit. This almost always provides read access to data, but it is harder to insert data using this technique, although not impossible (some exploits actually result in full root access of the target machine being achieved).
If you have a vulnerability that allows access to the key when using JWTs or one that allows database tables to be written to when using session identifiers, then it's game over - you are compromised because your user sessions can be hijacked.
So not more damaging necessarily, it all depends on the depth of the vulnerability.
Double check that the security of your JWT keys align with your risk appetite:
Where are they stored?
Who has access?
Where are backups stored?
Are different keys used in pre-production and production deployments of your app?
The ways to mitigate is as good practise dictates with any web app:
Regular security assessments and penetration testing.
Security code reviews.
Intrusion detection and prevention (IDS/IPS).
WAF.
These will help you evaluate where your real risks lie. It is pointless concentrating on one particular aspect of your application so much, because this will lead to the neglect of others, which may well be higher risk to your business model. JWTs aren't dangerous and have no more risk than other components of your system necessarily, however if you've chosen to use them you should make sure you're using them appropriately. Whether you are or not comes down to the particular context of your application and that is difficult to assess in a general sense, so I hope my answer guides you in the right direction.
When an attacker is able to get hold of the signing key in a JWT based system that means that he is able to get access to the server backend itself. In that case all hope is lost. In comparison to that, when the same attack succeeds in session based systems the attacker would be able to intercept username/password authentication requests to the backend, and/or generate sessions ids himself, and/or change the validation routines required to validate the session ids and/or modify the data to which the session id points. Any security mechanism used to mitigate this works as well for session systems as for JWT systems.
I'm writing a GWT application where users login and interact with their profile. I understand that each form entry needs to be validated on the server, however, I am unsure about potential security issues once the user has logged in.
Let me explain. My application (the relevant parts) works as follows:
1 - user enters email/pass
2 - this info is sent back to the server, a DB is queried, passwords are checked (which are salted and hashed)
3. if the passwords match the profile associated w/ the email, this is considered success
Now I am unsure whether or not it is safe to pass the profile ID back to the client, which would then be used to query the DB for information relevant to the user to be displayed on the profile page.
Is there a possibility for a potential user to manually provide this profile ID and load a profile that way? My concern is that somebody w/ bad intentions could, if they knew the format of the profile ID, load an arbitrary amount of information from my DB without providing credentials.
-Nick
What you are dealing with here is a session management issue. Ideally, you want a way to keep track of logged in users (using random values as the session key), know how long they have been idle, be able to extend sessions as the user is using the site, and expire sessions.
Simply passing the profile ID to the client, and relying on it to send it back for each request is not sufficient - you are correct with your concern.
You want to keep a list of sessions with expiration times in a database. Every time an action is executed that needs user permissions (which should be pretty much everything), check to see if the session is still valid, if it is, extend it by however long you want. If it is expired, kill the session completely and log the user out.
You can store your session keys in a cookie (you have to trust the client at some point), but make sure they are non-deterministic and have a very large keyspace so it cannot be brute forced to get a valid session.
Since you're logging a user in, you must be using a backend that supports sessions (PHP, .Net, JAVA, etc), as Stefan H. said. That means that you shouldn't keep any ids on your client side, since a simple id substitution might grant me full access to another user's account (depending on what functionality you expose on your client, of course).
Any server request to get sensitive info (or for any admin actions) for the logged in user should look something like getMyCreditCard(), setMyCreditCard(), etc (note that no unique ids are passed in).
Is there a possibility for a potential user to manually provide this profile ID and load a profile that way? My concern is that somebody w/ bad intentions could, if they knew the format of the profile ID, load an arbitrary amount of information from my DB without providing credentials.
Stefan H is correct that you can solve this via session management if your session keys are unguessable and unfixable.
Another way to solve it is to use crypto-primitives to prevent tampering with the ID.
For example, you can store a private key on your server and use it to sign the profile ID. On subsequent requests, your server can trust the profile ID if it passes the signature check.
Rule 1 - Avoid cooking up your own security solution and use existing tested approaches.
Rule 2 - If your server side is java then you should be thinking along the lines of jsessionid. Spring Security will give you a good starting point to manage session ids with additional security features. There will be similar existing frameworks across php too (i did not see server side language tags in the question).
Rule 3 - With GWT you come across javascript based security issues with Google Team documents and suggests XSRF and XSS security prevention steps. Reference - https://developers.google.com/web-toolkit/articles/security_for_gwt_applications
In an effort to increase performance, I was thinking of trying to eliminate a plain 'session cookie', but encrypt all the information in the cookie itself.
A very simple example:
userid= 12345
time=now()
signature = hmac('SHA1',userid + ":" + time, secret);
cookie = userid + ':' + time + ':' + signature;
The time would be used for a maximum expirytime, so cookies won't live on forever.
Now for the big question: is this a bad idea?
Am I better off using AES256 instead? In my case the data is not confidential, but it must not be changed under any circumstances.
EDIT
After some good critique and comments, I'd like to add this:
The 'secret' would be unique per-user and unpredictable (random string + user id ?)
The cookie will expire automatically (this is done based on the time value + a certain amount of seconds).
If a user changes their password, (or perhaps even logs out?) the secret should change.
A last note: I'm trying come up with solutions to decrease database load. This is only one of the solutions I'm investigating, but it's kind of my favourite. The main reason is that I don't have to look into other storage mechanism better suited for this kind of data (memcache, nosql) and it makes the web application a bit more 'stateless'.
10 years later edit
JWT is now a thing.
A signed token is a good method for anything where you want to issue a token and then, when it is returned, be able to verify that you issued the token, without having to store any data on the server side. This is good for features like:
time-limited-account-login;
password-resetting;
anti-XSRF forms;
time-limited-form-submission (anti-spam).
It's not in itself a replacement for a session cookie, but if it can eliminate the need for any session storage at all that's probably a good thing, even if the performance difference isn't going to be huge.
HMAC is one reasonable way of generating a signed token. It's not going to be the fastest; you may be able to get away with a simple hash if you know about and can avoid extension attacks. I'll leave you to decide whether that's worth the risk for you.
I'm assuming that hmac() in whatever language it is you're using has been set up to use a suitable server-side secret key, without which you can't have a secure signed token. This secret must be strong and well-protected if you are to base your whole authentication system around it. If you have to change it, everyone gets logged out.
For login and password-resetting purposes you may want to add an extra factor to the token, a password generation number. You can re-use the salt of the hashed password in the database for this if you like. The idea is that when the user changes passwords it should invalidate any issued tokens (except for the cookie on the browser doing the password change, which gets replaced with a re-issued one). Otherwise, a user discovering their account has been compromised cannot lock other parties out.
I know this question is very old now but I thought it might be a good idea to update the answers with a more current response. For anyone like myself who may stumble across it.
In an effort to increase performance, I was thinking of trying to
eliminate a plain 'session cookie', but encrypt all the information in
the cookie itself.
Now for the big question: is this a bad idea?
The short answer is: No it's not a bad idea, in fact this is a really good idea and has become an industry standard.
The long answer is: It depends on your implementation. Sessions are great, they are fast, they are simple and they are easily secured. Where as a stateless system works well however, is a bit more involved to deploy and may be outside the scope of smaller projects.
Implementing an authentication system based on Tokens (cookies) is very common now and works exceedingly well for stateless systems/apis. This makes it possible to authenticate for many different applications with a single account. ie. login to {unaffiliated site} with Facebook / Google.
Implementing an oAuth system like this is a BIG subject in and of itself. So I'll leave you with some documentation oAuth2 Docs. I also recommend looking into Json Web Tokens (JWT).
extra
A last note: I'm trying come up with solutions to decrease database
load. This is only one of the solutions I'm investigating
Redis would work well for offloading database queries. Redis is an in memory simple storage system. Very fast, ~temporary storage that can help reduce DB hits.
Update: This answer pertains to the question that was actually asked, not to an imagined history where this question was really about JWT.
The most important deviations from today's signed tokens are:
The question as originally posed didn't evince any understanding of the need for a secret in token generation. Key management is vital for JWT.
The questioner stated that they could not use HTTPS, and so they lacked confidentiality for the token and binding between the token and the request. In the same way, even full-fledged JWT can't secure a plain HTTP request.
When the question was revised to explain how a secret could be incorporated, the secret chosen required server-side state, and so fell short of the statelessness provided by something like JWT.
Even today, this homebrew approach would be a bad idea. Follow a standard like JWT, where both the scheme and its implementations have been carefully scrutinized and refined.
Yes, this is a bad idea.
For starters, it's not secure. With this scheme, an attacker can generate their own cookie and impersonate any user.
Session identifiers should be chosen from a large (128-bit) space by a cryptographic random number generator.
They should be kept private, so that attackers cannot steal them and impersonate an authenticated user. Any request that performs an action that requires authorization should be tamper-proof. That is, the entire request must have some kind of integrity protection such as an HMAC so that its contents can't be altered. For web applications, these requirements lead inexorably to HTTPS.
What performance concerns do you have? I've never seen a web application where proper security created any sort of hotspot.
If the channel doesn't have privacy and integrity, you open yourself up to man-in-the-middle attacks. For example, without privacy, Alice sends her password to Bob. Eve snoops it and can log in later as Alice. Or, with partial integrity, Alice attaches her signed cookie to a purchase request and sends them to Bob. Eve intercepts the request and modifies the shipping address. Bob validates the MAC on the cookie, but can't detect that the address has been altered.
I don't have any numbers, but it seems to me that the opportunities for man-in-the-middle attacks are constantly growing. I notice restaurants using the wi-fi network they make available to customers for their credit-card processing. People at libraries and in work-places are often susceptible to sniffing if their traffic isn't over HTTPS.
You should not reinvent the wheel. The session handler that comes with your development platform far is more secure and certainly easier to implement. Cookies should always be very large random numbers that links to server side data. A cookie that contains a user id and time stamp doesn't help harden the session from attack.
This proposed session handler is more vulnerable to attack than using a Cryptographic nonce for each session. An attack scenario is as follows.
It is likely that you are using the same secret for your HMAC calculation for all sessions. Thus this secret could be brute forced by an attacker logging in with his own account. By looking at his session id he can obtain everything except for the secret. Then the attacker could brute force the secret until the hmac value can be reproduced. Using this secret he can rebuild a administrative cookie and change his user_id=1, which will probably grant him administrative access.
What makes you think this will improve performance vs. secure session IDs and retrieving the userid and time information from the server-side component of the session?
If something must be tamper-proof, don't put it in the toddlers' hands. As in, don't give it to the client at all, even with the tamper-proof locking.
Ignoring the ideological issues, this looks pretty decent. You don't have a nonce. You should add that. Just some random garbage that you store along with the userid and time, to prevent replay or prediction.