Creating a very secure login with cookies and java - security

I'm designing a very secure login mechanism using play framework2. Since Play does not have a notion of sessions and keep things in the cookies (which I like) I was wondering what are the security measures I need to think about. We obviously going to use SSL to communicate the login credentials and also the cookie is going to be encrypted value of some of user's information like their email or userid. Is it possible that someone can sniff that cookie or get a hold of it from another user's cookie and reuse it? how can i make this more secure?

In fact the cookie isn't encrypted. It is signed. This signature comes from the application.secret in your application.conf.
It means that anyone can see the content of the cookie (and eventually try to spoof other sessions or change their login/id/token...)
From Play documentation :
Of course, cookie values are signed with a secret key so the client can’t modify the cookie data (or it will be invalidated).
I am not a security guru, but, if you keep your application secret secret, it seams enough to me.
Discussion about the strength of the signature are welcome !

Well if you want it really secure, you should general communicate via SSL not only for login. Otherwise someone can get the Cookie. The main-problem you have with the cookie-solution or better the play session is that you have no session-timeout. So imagine that I was able to get the cookie, I can use this user account forever. So you need something like a session-timeout. This becomes really tricky if there are more then one request from the same client, because both try to change the same cookie. A workaround is to handle the session timeout via cache, but have in mind that you need a distributed cache solution if you run in a cluster.
You can try to follow changes at https://launchpad.net/permsec the security solution I wrote. This is an open todo I must do.

If there's a risk of eavesdropping the communication and stealing the cookie, you can make things harder for the attacker. For example add IP address of the computer in the signed cookie. If someone else steals it, he'll have to use the same IP address as the victim. It's not impossible but it raises the bar.

Related

JWT Security with IP Addresses

I am building a Web Application using Angular 2 and the backend service built in ASP.NET Core Web API.
For authentication, I am thinking of using JWT and storing the token in a Secure HttpOnly Cookie.
For extra security, I am also thinking of capturing the IP Address for the user on the initial login and on each request after the initial login, revoking the token if the IP Address changes.
So the questions I have are:
Is this extra level of security worth it?
Will there be any problems with the IP check I am thinking of using? Based what I know about networking, I don't think an IP Address will legitimately change between request. Even if it does, I think it would be very rare. However I am not going to pretend I know enough about networking to confirm that.
Edit 1
(In response to an answer).
Thank you for answering my question. I have responded to a few of your responses.
My initial thought was that using JWT in a cookie to connect to an API is not the typical use case, why don't you use a standard MVC app then, but that's not your question and actually it's equally secure as long as the token is in a secure, httponly cookie (and of course the implementation is correct). It's just a bit unusual I think.
I am not sure why you consider using cookies this way unusual?
Is it because most of the time cookies are used for session state? I personally think storing a token in a secure cookie instead of keeping the token in a http header or local storage should be a very typical use case because of how much more secure it is. Unless I am missing something?
So I guess I will ask what is the disadvantage of doing it this way?
It depends. If you are worried about session theft, probably yes. If you keep the token in an httponly cookie (protected against xss), that's more secure than a token anywhere else, but still, your threat model may show different threats and validate your concern. The usual problem is you can't do this, see below.
This application will be dealing with a lot of PPI information so I do have a concern on token theft.
Most probably, there will be problems. It depends on your users, how and from where they use your application. If they use mobile devices, IP addresses will change a lot and such a solution is out of the question. If they are corporate users in a company internal network, it can be feasible. Anything inbetween is a gray area. A typical home user will have their IP changed once in a while, most people get dynamic IP allocation from their internet providers. An IP lease typically lasts a few weeks (at least where I live), but ISPs can configure it any way they want, it can be a day or even shorter.
My impression with IP address lease renew is majority of the time the client gets the same IP address. However I should not make that assumption I suppose?
However I can see this can be more of a problem with mobile devices. Some of the clients will be on the road often so this is a good point you have made that can become a problem.
One typical solution you can choose to do is offer this option on the login screen. If a user chooses to use IP address validation, he opts for greater security but accepts the fact that sometimes he may have to log in again. Or he can choose lower security with his session being more stable. Whether it's worth to explain this to your users is I think a business decision.
Never thought about giving the client an option which does sound like a good idea.
Edit 2
(In response to an answer).
Also I'm not sure whether your JWT only has a session id or if your server is stateless and all session data is in the JWT. In the first case, you don't even need the JWT, you could just pass the session id as normal, and standard .Net MVC does that for you. If it's session data too, JWTs are unencrypted by default, so session contents will be visible to endusers, which may or may not be a problem. (And a JWT is protected from tampering by its signature, so it's only about confidentiality, not integrity). Storing session data in the JWT and the JWT in the cookie may also face cookie size issues, depending on your target browsers.
My backend ASP.NET Core Web API will be stateless. The decision has already been made to use Angular so discussing is a moot point.
As for why I think using a JWT this way is a little unusual: I think JWTs are mostly used when tokens need to be passed to different URLs (to different services). For this purpose, httpOnly cookies are obviously inadequate because of the same origin rule. If you can afford using httpOnly cookies, you could just store your session info on the server side.
A much as I would like to discuss the above topic because my solution could be flawed, I think the powers that be may close this post for getting off topic?
Might be more appropriate to ask a new question targeted toward the above subject?
As for lease renews resulting in the same IP: Well, they don't always. It depends on your business case, but some ISPs give you IPs only for a short time. If it's ok for your users to get logged out once in a while, then it may be ok for wired (home) users. And it is definitely a big problem with mobile devices.
My initial thought was that using JWT in a cookie to connect to an API is not the typical use case, why don't you use a standard MVC app then, but that's not your question and actually it's equally secure as long as the token is in a secure, httponly cookie (and of course the implementation is correct). It's just a bit unusual I think.
On to the point, your question is very valid as is your concern about problems.
Is this extra level of security worth it?
It depends. If you are worried about session theft, probably yes. If you keep the token in an httponly cookie (protected against xss), that's more secure than a token anywhere else, but still, your threat model may show different threats and validate your concern. The usual problem is you can't do this, see below.
Will there be any problems with the IP check I am thinking of using?
Most probably, there will be problems. It depends on your users, how and from where they use your application. If they use mobile devices, IP addresses will change a lot and such a solution is out of the question. If they are corporate users in a company internal network, it can be feasible. Anything inbetween is a gray area. A typical home user will have their IP changed once in a while, most people get dynamic IP allocation from their internet providers. An IP lease typically lasts a few weeks (at least where I live), but ISPs can configure it any way they want, it can be a day or even shorter.
So reality is if you have a normal, usual userbase, you will most probably run into problems.
One typical solution you can choose to do is offer this option on the login screen. If a user chooses to use IP address validation, he opts for greater security but accepts the fact that sometimes he may have to log in again. Or he can choose lower security with his session being more stable. Whether it's worth to explain this to your users is I think a business decision.
Update in response to Edit 1 :)
As for why I think using a JWT this way is a little unusual: I think JWTs are mostly used when tokens need to be passed to different URLs (to different services). For this purpose, httpOnly cookies are obviously inadequate because of the same origin rule. If you can afford using httpOnly cookies, you could just store your session info on the server side. Also I'm not sure whether your JWT only has a session id or if your server is stateless and all session data is in the JWT. In the first case, you don't even need the JWT, you could just pass the session id as normal, and standard .Net MVC does that for you. If it's session data too, JWTs are unencrypted by default, so session contents will be visible to endusers, which may or may not be a problem. (And a JWT is protected from tampering by its signature, so it's only about confidentiality, not integrity). Storing session data in the JWT and the JWT in the cookie may also face cookie size issues, depending on your target browsers.
As for lease renews resulting in the same IP: Well, they don't always. It depends on your business case, but some ISPs give you IPs only for a short time. If it's ok for your users to get logged out once in a while, then it may be ok for wired (home) users. And it is definitely a big problem with mobile devices.
I think you can do it with JWT and IP. When the user logs in. Capture the IP for the length of the session. At every login Capture IP then use that to validate the Token is from the owner who started the session. If another IP hits the system. force a revalidate and new token. IP+JWT+Password = login. If you had mobile apps that required 1 login and always remember the login. User never has to enter login again. Then cache the userid\password in the application {securely} and then resend it automatically when the IP changes. JWT is secure when using SSL Difference between SSL and JWT
Sorry for reviving this, but lately I have been thinking a lot about encryption and security and thought of something (that I guess is pretty similar to what HTTPS does)
When user logs in, the server responds with a normal greeting (user info, JWT and whatever other data you need to pass) + you will pass a public key
Have a backend that supports any asymmetric encryption method (I like RSA) and have your front (also needs to run the same encryption method) end receive the public key, encrypt the data, and send it to the server with every subsequent request.
If any of the data that the user needs to provide changes, revoke.
You can even keep track of a clock, if its off by too much, revoke.
For extra layer, have the client transmit a public key on login/signup and boom, hermetic comms like a hazmat suit.

How secure are sessions?

From what I understand and have read about sessions, a website, like Facebook, will store a code on your computer that your computer sends back to Facebook every time you visit their site. This saves you the trouble of logging in every time you want to see your news feed.
My question is, how is this in any way secure? Can't anyone write a simple program to find this code on your computer - just like Facebook does? Or if you let your geeky friend use your computer, how do you know he doesn't copy your session codes and just use your account from somewhere else?
I read that sessions are more secure than cookies because cookies actually carry information like your username, password and other vital info. But if a session code can provide access to your whole account anyway, isn't a session just as insecure?
Are there any other factors at play that I don't know about or are sessions really this insecure?
My question is, how is this in any way secure? Can't anyone write a simple program to find this code on your computer - just like Facebook does?
Yes. Someone can do that. And they can steal your session credentials. If your computer is compromised, you can't build any form of security on top of that. If you can't trust the computer, you can't trust the browser. And if you can't trust the browser, there's no way you can possibly trust the website.
So we need to start with a fundamental assumption. To secure the website, we must assume the browser (and hence the computer) is secure.
If you can get code onto the computer to search for the session identifiers, it's game over already, since you can typically do much worse while you're there.
Or if you let your geeky friend use your computer, how do you know he doesn't copy your session codes and just use your account from somewhere else?
You don't. This is why you shouldn't let friends use your computer (among other reasons).
There are some techniques that can be done to verify the session came from the specific computer. But they tend to be either insecure (like verifying user agents) or fragile (like verifying IP addresses).
I read that sessions are more secure than cookies because cookies actually carry information like your username, password and other vital info. But if a session code can provide access to your whole account anyway, isn't a session just as insecure?
Sessions are no more secure than cookies, because the session uses a cookie for identification. Sure, the specific data doesn't leave the server (so it doesn't leak), but the attacker can resume the session.
Are there any other factors at play that I don't know about or are sessions really this insecure?
The key here is who are you trying to protect against. Specifically, what threat model:
A friend, who you give admin access to your computer (let them borrow with a privileged account)
You can't reliably protect against that. If your users let others borrow their computer, you, as a website operator, can't help that unless you don't use a session at all and require users to authenticate every action.
Simply don't do it, or give them a clean guest account. Or better yet, use a chromebook, and let them sign in with their own account.
An attacker getting code onto the computer
You can't help that.
Someone snooping the network traffic (read-only) like a network packet sniffer.
Use TLS (HTTPS)
Someone man-in-the-middle attacking the network traffic (read/write)
Use TLS (HTTPS)
Someone attacking the server
Secure your server!!!
In general, to figure out how to secure something, you need to consider the vector the attack is going to come from. Some attacks you simply can't defend against. And some, you just need to educate the user about.
Session IDs are stored in cookies, so their security is the same as that of cookies.
Cookies are handled by your browser, which takes care of protecting them to the extent that it's possible.
No website can "ask your browser for a cookie" (and that is not what Facebook does). Instead, when accessing facebook.com, your browser sends along your facebook.com cookies, but not your google.com cookies.
Of course, "writing a simple program to find this code" would be easy, but distributing it wouldn't be that easy (i.e. you're talking about distributing malware), and it's definitely not what Facebook does to get access to the relevant session cookies.
There are several additional ways to protect cookies from unauthorized access (to a certain extent). One of them is to make them "HTTP-only", so that they aren't accessible in Javascript (they'll still be sent to Facebook's servers, but the browser won't expose them to anything else).
Note that cookies are indeed as secure as the browser itself. If your browser is "compromised" (by your geeky friend), then so are your cookies, and so is your session.

How do I prevent session hijacking by simply copy a cookie from machine to another?

Most Web Applications use cookies to manage the session for a user and allow you to stay logged in even if the browser was closed.
Let's assume we did everything by the book to make sure the cookie itself is safe.
encrypt the content
set http only
set secure
ssl is used for the connection
we check for tampering with the content of the cookie
Is it possible to prevent someone with physical access to the machine to copy the cookie and reuse it on another machine and thus stealing the session?
It doesn't make sense to "protect" against this. If this kind of copying happens, then either:
The end user did it on purpose because they wanted to change computers. This is, of course, not something you should care about or be concerned about.
An attacker has already compromised the user's browser and gotten access to the cookies stored inside. By definition this cookie is a secret that proves that the identity of the HTTP client. If the attacker already has access to it, they can already use it in any number of ways of their choosing that you won't be able to prevent or distinguish from the real user accessing the server legitimately.
This risk is inherent in using cookies to authenticate sessions: the cookie is a bearer token, anyone who can present the cookie is authenticated.
This is why you see further protections such as:
automatic log out after a certain amount of time, or period of inactivity;
device fingerprinting;
requiring re-authentication for critical actions (e.g. making a bank transfer or changing your password).

Is secure to store user data like logged status and id in cookies?

The question says pretty much everything. My point is, is the user able to change his cookie's values in order to appear "logged", when he's not really logged?
Cookies aren't secure. As others here have pointed out, you shouldn't trust any data received from the client, period. That said, cookies are often used to store Session IDs for logged in users, which is sort of what you're asking.
Signing your cookies will help you detect if they've been tampered with on the client. Basically, you create a HMAC of the keys/values and a secret key, known only to the server. On each request, you re-compute the MAC: if it matches the previous value, all is well; if not, you reject the request.
For more sensitive data, you can optionally encrypt the cookies. Most web frameworks will allow you transparently do these using some kind of "middleware" external to your application code, so the signing/validation and encryption/decryption happens for each request.
Also, you should know that simply securing your cookies doesn't guarantee, er...security :) You might still be vulnerable to Cross-site Request Forgeries.
For more information on cookies, check out this article.
So then if I change the user_id=1 do I become the administrator?
What if i type this into the address bar:
javascript:document.cookie=user_id=1&logged_in=true
In general it is a horrible idea to re-invent the wheal. Especially when it comes to security, a cookie should always be a very large random value. Whatever platform you are using should have a session handler already built for you.
Usually a server generated token is stored in a cookie. When the cookie expires the token is lost and the user needs to sign in again. You can't fake the token. It's not a boolean value stating whether the user is signed in or not.
Anything you get from the client (including cookies) is unsafe. The safe way is to set a cookie with a random hash, log the hash in the database together with an ID and a timestamp (and perhaps even IP) and then check the incoming cookies against the stored hashes. If you set the cookies to expire after some time, make sure you also reject them on the server if they arrive when they should not.

Exists a way to prevent cookies from getting stolen?

in Web 2.0 applications many users usually want to stay logged in ('remember me' flag) and on the other hand their cookie can give access to very private data. Is there a way to prevent that somebody who steals the cookie - directly from the computer or via sniffing - can use the cookie to get access to the user's data? Always HTTPS is not an option.
Thanks, Bernd
[Edit] Connect the IP address to the cookie is not an option either.
KISS -- just use sessions so that you're using an ID that is already automatically created by the server-side scripting language of your choice. That's hard enough to guess. Then, if it's stolen, store the IP address and user-agent of the visitor in the session (making sure never to output that) and only consider the session valid only if the already stored IP address and user agent match that which is found for the remote client.
In this scenario, the attacker would have to do the following three things:
Steal the victim's cookies
Spoof the correct IP address
Spoof the correct User Agent
It also helps to make sure that the attacker doesn't already know all of the things he/she would have to do in order to correctly take over a victim's session. IE: They may assume just the cookie is needed and then fail... and have to figure out everything else through a very long trial and error. In this way, you gain security through obscurity and through difficulty, depending on the skill of the attacker and his/her existing knowledge of the system.
Bernd -- the trouble with anything done over standard HTTP is that it's plaintext; anyone can fake anything. IP Spoofing is a bit more challenging to do than just plain cookie stealing, so tying to the IP tends to be what people do. Like you said, that does not work very well with highly dynamic environments.
The only mostly secure way I can think of is to use HTTPS to place and verify a "permanent" cookie, and then place (in the same HTTPS session) a short-lived session cookie. The rest of the communication can be done over regular HTTP, using the session cookie to authenticate.
That way, fewer resources are used in supporting encryption (just the handshake), the permanent cookie is not exposed -- it's only transmitted under encryption -- and stealing the session cookie opens up to only limited risk, since that cookie will quickly expire.
All that being said -- don't let users click "remember me" on a site that contains truly sensitive data! That's why Banks don't do it..
Hope this helps.
About storing complex cookie ids and associated IPs in a database -- you don't really have to do that. If you have a secret key K, it is enough to encrypt the user's ip with your K, and place the result {IP}K as a cookie. As long as your key is secure (and the crypto hasn't been broken -- but if that happens, we have bigger problems), this is safe.
Perhaps using a Session ID and token (a hash based on the IP, a salt, and the Session ID), that is regenerated every request (use a fast hashing algorithm) would be a good approach? I store session data in a database (currently), and this means I have a two query overhead every request. It works like this:
Select where SID and TOK match.
Verify a token generated based on current client matches that in the database.
deserialise the data into a property.
Scripts etc happening.
Serialise the updated data, regenerate the SID/TOK, and update DB where SID/TOK = old sid and tok, updated data and new sid and tok. Set the cookie to the new SID and TOK.
In this way, firstly cookies are bound to whatever I base the token on (in this case, remote address), and if that is stolen and client data spoofed, the cookie is only useful for one request anyway - by the time the cookie is intercepted, it is useless.
The only perceivable weakness I can see is if the attacker managed to grab a cookie, spoof, and use it, before the real person could do another request. There are a few ways to solve this that I need to think about. The overhead is two queries and generating a token hash twice (once for verification, once for replacement).
Put a lid on the cookie jar.
Jokes aside, the best option has already been stated - make the cookie an obscure ID and tie it to an IP address lookup on the server side. Since you edited to say you cannot tie it to an IP address, that leaves the obscure ID part. Your options are limited with cookies - the minute you place something on the client, it becomes a risk.
Store a cookie that is an obscure ID into your local server database. Do a server-side DB lookup based on the ID provided in the cookie. Be sure to make the ID sufficiently complex that it cannot be easily guessed. Map the ID to the IP Address of the user. If their IP changes, then force them to log in again, and create a new ID.
On second read, it sounds like you want a high level of security with your hands tied. The user must have the choice to remain logged in and thus increase his/her risk. You can implement all the security in the world from the application's and server's point of view, but if the user forgets their laptop on a table in Tim Horton's (Canadian Starbucks), then none of it will do you any good.
Leave the choice up to the user as to whether or not they remain logged in, and give them a warning about their information being at risk.
Bernd - you say connecting the IP address to the cookie is not an option, I'm assuming that's b/c the user could be connected via DHCP, and thus could come in under a different IP each time. Have you considered tying the cookie to the DNS host name? You could encrypt the cookie using a private key, and store it on the user's box. Then whenever they come in, check the cookie, un-encrypt it, and then check the user's current DNS Host name against the one in the cookie. If it matches, you allow them in. If not, you don't allow the auto-login.
FYI - in ASP.Net, to get the DNS host name of the user's box, just look at
Page.Request.UserHostName

Resources