I inherited a coldfusion application. The code is very old (think Allaire days) and I've been slowly upgrading it. Recently, we endured pentration testing, which failed in numerous areas. My focus at this moment is the login functionality, specifically how to store and use cookies. We recently upgraded to CF 2018 on Windows.
The site is only accessible via RDS currently, but will be made available via the general web in the near future.
Currently, the code sets a "rememberme" cookie onLogin, as follows, using a heap of obfuscation. I think this was borrowed from a Ben Nadel example: https://www.bennadel.com/blog/1213-creating-a-remember-me-login-system-in-coldfusion.htm
<cfset strRememberMe = (
CreateUUID() & ":" &
SESSION.User.ID & ":" &
SESSION.User.Name & ":" &
SESSION.User.Billing & ":" &
SESSION.User.Admin & ":" &
SESSION.User.Reversals & ":" &
CreateUUID()
) />
<cfset strRememberMe = Encrypt(
strRememberMe,
APPLICATION.EncryptionKey,
"cfmx_compat",
"hex"
) />
<cfcookie
name="RememberMe"
value="#strRememberMe#"
expires="never"
httponly="true" <!--- Set in CFAdmin so not reqd here --->
/>
Several user permissions are included in this cookie, flagging the user as being able to access certain parts of the site and/or perform certain functions.
I would like to keep any unnecessary data completely out of the cookie, perhaps keeping only the userID there. A check could be made, perhaps in application.cfc onRequest() method, to check for the cookie and query the database, then set session variables related to user permissions. Currently, application.cfc onSessionStart() parses the user permissions out of the cookie to create the session-scoped variables. Problem I see with only having the raw UserID in the cookie is that the UserID could be rather easily guessed, so some type of obfuscation or encryption would probably still be necessary.
I realise from my reading that cfmx_compat provides weak encryption.
I'm after the cleanest, most effective way to secure the cookie from any type of third-party or MITM abuse/attack, and make use of it in the application. I've read just about everything on the internet about this and people are doing and suggesting different things. My brain is overloaded with ideas right now. I don't want to be fancy, just effective.
The site doesn't have SSL or TLS right now, but will be implemented soon, which should help matters security-wise.
Think of the remember me with the same security concerns as normal login credentials. Do not include any sensitive info, rather save all other data in the database and only access it after the user is authenticated.
In the cookie, have a way to identify a user and a secret with sufficient length/entropy. The secret should be hashed (ex: bcrypt) in the database, so if someone sees your database they can't simply send the data in a cookie to authenticate as any user. You can include the username in the cookie or create a random string for each user that can be used instead.
Did you have other concerns or questions?
Related
My web application's authentication mechanism currently is quite simple.
When a user logs in, the website sends back a session cookie which is stored (using localStorage) on the user's browser.
However, this cookie can too easily be stolen and used to replay the session from another machine. I notice that other sites, like Gmail for example, have much stronger mechanisms in place to ensure that just copying a cookie won't allow you access to that session.
What are these mechanisms and are there ways for small companies or single developers to use them as well?
We ran into a similar issue. How do you store client-side data securely?
We ended up going with HttpOnly cookie that contains a UUID and an additional copy of that UUID (stored in localStorage). Every request, the user has to send both the UUID and the cookie back to the server, and the server will verify that the UUID match. I think this is how OWASP's double submit cookie works.
Essentially, the attacker needs to access the cookie and localStorage.
Here are a few ideas:
Always use https - and https only cookies.
Save the cookie in a storage system (nosql/cache system/db) and set it a TTL(expiry).
Never save the cookie as received into the storage but add salt and hash it before you save or check it just like you would with a password.
Always clean up expired sessions from the store.
Save issuing IP and IP2Location area. So you can check if the IP changes.
Exclusive session, one user one session.
Session collision detected (another ip) kick user and for next login request 2 way authentication, for instance send an SMS to a registered phone number so he can enter it in the login.
Under no circumstances load untrusted libraries. Better yet host all the libraries you use on your own server/cdn.
Check to not have injection vulnerabilities. Things like profiles or generally things that post back to the user what he entered in one way or another must be heavily sanitized, as they are a prime vector of compromise. Same goes for data sent to the server via anything: cookies,get,post,headers everything you may or may not use from the client must be sanitized.
Should I mention SQLInjections?
Double session either using a url session or storing an encrypted session id in the local store are nice and all but they ultimately are useless as both are accessible for a malicious code that is already included in your site like say a library loaded from a domain that that has been highjacked in one way or another(dns poison, complomised server, proxies, interceptors etc...). The effort is valiant but ultimately futile.
There are a few other options that further increase the difficulty of fetching and effectively using a session. For instance You could reissue session id's very frequently say reissue a session id if it is older then 1 minute even if you keep the user logged in he gets a new session id so a possible attacker has just 1 minute to do something with a highjacked session id.
Even if you apply all of these there is no guarantee that your session won't be highjacked one way or the other, you just make it incredibly hard to do so to the point of being impractical, but make no mistake making it 100% secure will be impossible.
There are loads of other security features you need to consider at server level like execution isolation, data isolation etc. This is a very large discussion. Security is not something you apply to a system it must be how the system is built from ground up!
Make sure you're absolutely not vulnerable to XSS attacks. Everything below is useless if you are!
Apparently, you mix two things: LocalStorage and Cookies.
They are absolutely two different storage mechanisms:
Cookies are a string of data, that is sent with every single request sent to your server. Cookies are sent as HTTP headers and can be read using JavaScript if HttpOnly is not set.
LocalStorage, on the other hand, is a key/value storage mechanism that is offered by the browser. The data is stored there, locally on the browser, and it's not sent anywhere. The only way to access this is using JavaScript.
Now I will assume you use a token (maybe JWT?) to authenticate users.
If you store your token in LocalStorage, then just make sure when you send it along to your server, send it as an HTTP header, and you'll be all done, you won't be vulnerable to anything virtually. This kind of storage/authentication technique is very good for Single-page applications (VueJS, ReactJS, etc.)
However, if you use cookies to store the token, then there comes the problem: while token can not be stolen by other websites, it can be used by them. This is called Cross-Site Request Forgery. (CSRF)
This kind of an attack basically works by adding something like:
<img src="https://yourdomain.com/account/delete">
When your browser loads their page, it'll attempt to load the image, and it'll send the authentication cookie along, too, and eventually, it'll delete the user's account.
Now there is an awesome CSRF prevention cheat sheet that lists possible ways to get around that kind of attacks.
One really good way is to use Synchronizer token method. It basically works by generating a token server-side, and then adding it as a hidden field to a form you're trying to secure. Then when the form is submitted, you simply verify that token before applying changes. This technique works well for websites that use templating engines with simple forms. (not AJAX)
The HttpOnly flag adds more security to cookies, too.
You can use 2 Step Authentication via phone number or email. Steam is also a good example. Every time you log in from a new computer, either you'll have to mark it as a "Safe Computer" or verify using Phone Number/Email.
I need to clear a concept.
I'm tracking unauthenticated users in my Django social networking web-app via setting a temp_id that's set in the request.session dictionary as soon as a new user hits the web-app's landing page. The code is is simply:
temp_id = request.session.get('temp_id',None)
if not temp_id:
request.session['temp_id'] = get_temp_id()
So far so good.
Apart from saving a temp_id in request.session, another technique I could have used is setting a browser cookie explicitly for unauthenticated users like so:
if not request.session.exists(request.session.session_key):
request.session.create()
The concept I'd like to clarify is are these approaches equivalent?
I feel they are. My reasoning is: if a browser cookie is just a reference to a Session stored in the DB, then if cookies were turned off, matching a Session for that user would be impossible. So regardless of whichever approach I take, I'll be relying on the browser's ability to store a cookie.
Or in other words, both methods of allotting a temp_id to an unauthenticated user are, under the hood, quite similar. The only difference is that browser cookies are less secure than session variables (over HTTPS).
Can someone point out whether this line of thinking is correct? Or is my approach wrong? I'm essentially trying to ascertain which approach to take for reliably tracking unauthenticated users once they hit my app's landing page and move about.
I have two web applications different things, but authentication is done only by one (using python and tornado), id like to have the second application access the credential of the user transparently, currently I can read the cookie of a logged in user via the header: Access-Control-Allow-Credentials , so how would i access the cookie, so i can store it (mongodb/redis/anywhere-but-mysql), and retrieve it in the second app?
what I've tried:
self.set_secure_cookie('cookie_name') # works i can see the cookie in subsequent request headers
self.get_secure_cookie("cookie_name") # just after setting the cookie returns None
what I was thinking is to store the encrypted value and compare it later in the second application as and when needed, is this sensible? all that i need to do is to ensure the user is
logged in and they exist in out list of users as of the moment.
So you've managed to set a cookie by one of the servers and then retrieve it on the second? If so, great! That's the trickiest part (imho).
Now there are two ways to go.
Store data in the cookie
Tornado have, as you've noticed, support for secure cookies. This basically mean that you can store data in the cookie and sign it with a secret. If both you servers have the same secret they can verify that the cookie data is not altered and you have successfully distributed data between the two servers. This decentralised alternative is not suitable if you need to store much data in the session.
A shared DB (or an API that the other server can use)
If you go with this solution you just have to store a session key in the cookie. No need to use secure cookie since it's no data stored there. You simply generate a SSID, e.g. ssid = uuid.uuid4().hex, store that in a cookie called something like ssid and also add a record to the DB along with all session data you want to store. I really like Redis for this since you can set the expire on creation and don't have to worry about that anymore, it's pretty fast and the best thing is that there's a nice and easy async lib you can use that plays nice with tornado.
On the time of login, coldfusion server assigns me a CFID and a CFTOKEN. Later on using those CFID and CFTOKEN how can I check if my session still exists or not.
In other words I want a function that will take CFID and CFTOKEN and will tell if the session related to those CFID and CFTOKEN still exists or not.
Thanks
The easiest way to achieve this would be to set a flag in the session when your user logs in.
for example
<cfset session.loggedin = true />
then when you want to check if the user still has a valid session you can do
<cfparam name="session.loggedin" default="false" />
<cfif NOT session.loggedin>
<!--- do something here --->
</cfif>
There is nothing wrong with Chris' answer and is usually the standard norm when checking for sessions.
These two cookies are meant to "link" your browser with your session, not to actually maintain that session (in fact, I believe these cookies are set to expire in 30 years(?) and are even ignored if you're using J2EE session management if I'm not mistaken). From the docs:
To use client and session variables, ColdFusion must be able to
identify the client. It normally does so by setting the following two
cookie values on the client’s system:
CFID: A sequential client identifier
CFToken: A random-number client security token These cookies uniquely identify the client to
ColdFusion, which also maintains copies of the variables as part of
the Session and Client scopes.
As you can read here, Ben Nadel did some playing around with CFID and CFTOKEN where CF used the same CFID and CFTOKEN cookies to create NEW sessions after it had expired.
As for your 'ColdFusion Proper' way, you could look into using CFLOGIN and other security tags which are meant to assist in handling authentication but I don't believe many people use it because maintaining your session is very easy as Chris demonstrated.
When setting Cookiee on the server with properties(httpOnly and secure=true), does that mean it will only be secured during the communication beween server and client, but not after that?
In other words, if the value was originally in plainText -will it also be stored on the client side with plainText (after traveling with https ) -making it unsafe/vulnerable?
1) Do passwords needs to be always encrypt befors sending (even when using https)?
2) Where is httpCookiee (with secure=true) stored? and is this storage access is protected?
You probably don't want store the password.
What you need is store some "user is already authenticated" flag.
After all, you should learn about "digest access authentification". Storing hashed data is always plus.
This answer is too short, mainly bacause here is too much possibilities - and too much open questions.
Handling returning users:
You can manage (server side) an session database. in the cookie you storing only session ID. when the user authenticate itself, you're store into your server side database his status: "logged in". when he log out, you change in the DB status: "logged off".
Handling returning users has nothing with "storing passwords" in any way. You for example can authenticate users by external auth-services, like open-id, twitter, facebook etc., you're only storing his status by some session-ID or similar.
Browsers usually can store user-names/passwords, but this all time should be the user responsibility. When the user want only remeber his passwords, you should not store it in any way.
Why you want complicating your app and security mechanisms with storing encrypted passwords in cookies - what is not a correct solution - from any point of view?
Simple flow:
When an new user comes to your site - you assign him an new session-ID and store the SID into a cookie
when he login (via https) - you're store in your DB = "sessionID" -> "logged in"
when he return after a week, you can (server side) either accept his session-ID from the cookie - and from DB you can get his "logged-in" status, or, you can force login him once again (for example because of expiration)
all of the above is without any risk storing passwords in any way
1) I think so. Because even with secure flag, cookie will be stored in browser cache in plain text
2) It depends on browsers and OS. For Safari in Mac, you can find it in your ~/Library/Cookies/Cookies.plist You can see cookies with Secure flag but in plain text. It may be protected so only owner can see, but it never be good idea to have plain password anywhere in your computer
Once the secure flag is set to true, the cookie will be stored encrypted in the client even after the browser is closed. As you say it is unsafe/vulnerable.
Resp. 1)
Passwords can be encrypted before sending using Javascript, but it doesn't make much sense because https is doing the encryption for you.
Resp. 2)
The cookies are stored in the browser folder. Anybody can open the folder and see the cookies with a text editor.
The browser will handle the passwords for you. Just using a <input type="password"> and using SSL is secure enough.
And, avoid at all costs storing passwords in cookies.