Tips on signed cookies instead of sessions - php

I'm considering ditching PHP's $_SESSION (i.e. the server-side session handling, to add some language-agnostic flavor) and using signed cookies instead, since I've heard so much good about them (Flickr uses them, so they ought to be good enough for me too).
I understand the basic context of the technique: Use cookies freely to pass key-value pairs from client to server, and sign them to make sure that the values aren't tampered with.
But what would be a good way to implement the signing part? Also; since the traffic will probably be HTTP, is there a good way to send sensitive data (such as a user's password) with this method, while working against cookie-stealing and/or tampering?

Why bother?
I wouldn't use this technique for sensitive data. It can be useful in combination with a regular session though - you can give the client a cookie with a normal session id, but also include all those key/value pairs that your application needs on every page. This way, you can avoid hitting your session storage for every page request.
You should aim to keep the amount of data pretty tight, since it will be sent with every request.
With that in mind, onwards...
Signing data with a hash
If the data isn't sensitive, you can sign the values with sha1 hash made from a combination of the key/value pairs and a shared secret. e.g.
$values=array(
'user_id'=>1,
'foo'=>'bar'
);
$secret='MySecretSalt';
$plain="";
foreach($values as $key=>$value)
{
$plain.=$key.'|'.$value.'|';
}
$plain.=$secret;
$hash=sha1($plain);
Now give the client a cookie with all the values and the hash. You can check the hash when the cookie is presented. If the hash you calculate from values presented by the client doesn't match the expected hash, you know the values have been tampered with.
Encrypting sensitive data
For sensitive data, you'll need to encrypt the values. Check out the mcrypt extension which offers a lot of cryptographic functions.
Cookie theft
With regards to cookie stealing, if you're putting user credentials into a cookie and trusting it, then someone who obtains that cookie can impersonate that user until the password is changed. A good practice is to remember how you authenticated a user, and only grant certain privileges if the user explicitly logged in. For example, for a forum you might let someone post, but not change their account details like email address.
There are other techniques for "autologin" cookies, involving giving such cookies a token value which you only allow to be used once. Here's a good article on that technique.
You could also look at including the client IP in a signed cookie, and if it doesn't match the IP presenting the cookie, you get them to log in again. This provides more protection, but won't work for people whose apparent IP address keeps changing. You could make it an optional feature, and give the user a way to opt out. Just an idle thought, I've not seen that done in practice :)
For a nice article which explains session theft, hijack and fixation see Sessions and Cookies which offers a few more techniques to try, such as using the User-Agent header as an additional signature.

I made CookieStorage exactly for this purpose. All stored values are securely signed with your private key via RIPEMD160 hashing (and salted with time), and optionally encrypted with RIJNDAEL256.
Each value is stored with the timestamp, which is retrievable.
Signed example.
Encrypted example.
If you prefer, you can use the hash/encrypt/decrypt functions of your choice.

Signed cookies in PHP
The other answers to this question are a bit outdated. PHP 5.2 added the httponly parameter to the setcookie function, effectively adding native signed cookie support. According to the setcookie function httponly parameter documentation:
"When [set to] TRUE the cookie will be made accessible only through the HTTP protocol. This means that the cookie won't be accessible by scripting languages, such as JavaScript. It has been suggested that this setting can effectively help to reduce identity theft through XSS attacks (although it is not supported by all browsers), but that claim is often disputed"
Setting this parameter to true will also disable the ability to edit this cookie using other browser-based tools, such as Chrome's DevTools. To make the signed cookie even more secure I highly recommend narrowing down the path or domain it uses. You can specify those using the path and domain parameters. And of course it never hurts to secure the cookie using the secure parameter if your website is being loaded over HTTPS. The result will be a line like this:
setcookie('signedCookie','uneditable value here', 0, '/', 'www.example.com', TRUE , TRUE);
Why use signed cookies?
There are, in fact, specific situations in which signed cookies are helpful while other methods, such as a session, are not. For example, let's assume the website/application in question uses a load balancer to improve performance. Now let's also assume that that loads balancer has multiple physical servers from which files are being served and a sticky session option is not available. In such a situation signed cookies are virtually the only secure way to preserve state in PHP.

Related

Security questions from login with SESSIONS (PHPSESSID) or COOKIES if is same.. or not?

I have several questions about SESSIONS and COOKIES, I read in internet and all people recommend use SESSIONS (for security) but.. Not is same save the ID login in one session (phpsessid) that save in one cookie?
I tested this:
I copied my PHPSESSID ID (cookie) from my login account from a website
( in chrome) and insert my PHPSESSID (cookie) in another browser (in
opera) with VPN and I can access in this account.
What is the security here? if anyone can guess or hijack my cookie PHPSESSID ID is same if I use a Cookie to saving the login id, or not?
My question is.. Dont is more secure use a secure cookie ID like in wordpress, encrypting ID and checking in DB the IP and USER_AGENT ?
Now, I using this:
I create a random ID and save in one cookie (when the user login is success)
And check if this ID exist in the DB, check if the IP (saved in DB) and USER_AGENT (saved in DB) is equal. if not, login another time
Anyone can me guide a little? Thx you for read.
You should ask yourself this: "How easy is it to guess the randomly generated random id?".
If your answer to this question is "very easy" you should make it harder to guess. Use a UUID or some other form of securely random ID.
If you answer is "quite hard" you should not have to worry about this. The only attack vector you are offering is to be able to guess a randomly generated id.
You can read more about "guessing the PHPSESSID" here.
In general it should not be necessary to check the IPs of the user (as a side note, you open up yourself to all the stuff in the GDPR by doing this) or their User-Agent as both things might change during the sessions lifetime.
The key point about sessions is that they are a server-side storage. In other words, your program writes whatever it sees fit and it reads back exactly what it wrote before because information cannot be tampered by clients as it happens with cookies. Additionally, the information remains hidden to client's eyes so it can store confidential or just internal uninteresting information. Last but not least, a PHP session allows to store most data types supported by PHP. A cookie can only store plain text.
The weak link in sessions is that HTTP is a stateless protocol so the client needs to identify itself on every request (unlike it happens in other network protocols as FTP, SSH or SMTP). Earlier implementations would transmit the session ID in the URL itself. It was later improved to only use cookies and cookies can be configured to be restricted to encrypted connections. But, yes, if something intercepts your HTTP traffic and finds out your session ID he can easily impersonate you because most sites don't care about implementing further checks. However, that's why HTTPS is encouraged nowadays.

Is PHP Session more secure or SetCookie?

What bit is more secure?
function login_customer($customer_details) {
//Set a cookie to login the customer
setcookie("Str_CUST_LOGIN", 1, time()+3600);
setcookie("Str_CUST_EMAIL", $customer_details['customers_email']);
setcookie("Str_CUST_ID", $customer_details['customers_id']);
//Update the cart
return true;
}
or is this below. The script uses IF ELSE statements. Nightmare application for old client.
function login_customer($customer_details) {
//Set a cookie to login the customer
$str_HA_CUST_LOGIN="1";
// the customer details var gets info from a mysql escape form
// so mysql /xss is stopped
$str_HA_CUST_EMAIL=$customer_details['customers_email'];
$str_HA_CUST_ID=$customer_details['customers_id'];
$_SESSION["loggedIn"]=$str_HA_CUST_LOGIN;
$_SESSION["userEmail"]=$str_HA_CUST_EMAIL;
$_SESSION["userID"]=$str_HA_CUST_ID;
return true;
}
I am trying to improve it and lock sessions down. Not done any Salt, MD5 based sessions strings yet as I was thinking of a database session - only issue here is MySQL is so overloaded we had to make a master and cluster load balancer on cloud servers. 200+ average orders per second on a quite day. So I want sessions??
Cookies can be easily forged and tampered by a client. So if an attacker knows what cookies the application expects, he/she can forge the cookies or alter the cookie values at his/her will.
In your case it would probably be possible to authenticate as a arbitrary customer solely on the basis of knowledge of the customer ID (and/or the e-mail address).
The problem with this is that you mix up identification (‘Who is the user?’) and authorization (‘Can he/she prove it’s really him/her?’). Because both an ID and an e-mail address are used for identification as they are both unique and some kind of public (i. e. not just known to you) and thus not qualified for authentication. So don’t use identification information for authentication as well.
Now if you think I’ll just put the password in a cookie as well that would fulfill the authentication aspect, don’t do that either. Because there are attacks where an attacker can read the contents of a cookie (e. g. Cross-Site Scripting) and thus would be able to obtain the authentication data.
Use the session container instead to store the sensible information on the server side. But with sessions you still need to be aware of session related attacks like Session Hijacking or Session Fixation.
Cookies and their data are sent over the wire on EVERY request to the page. If you're embedding site-critical data in the cookies, it will be trivial to mangle/steal that data while the page requests is "in flight".
Sessions, by comparison, store all data on the server. The only thing that goes between the client and the server is the session's ID token. Stealing the session token allows an attacker to assume the victim's identity, but then they don't gain any more abilities than the user had already.
e.g. If you're sending out a cookie has_super_user_powers=false, then don't be surprised when someone hacks the cookie to make it true instead. Saving that flag in the session makes it unchangeable by the remote user, as the value never leaves your server in the first place.
Both can be stolen, but the value of cookies can be read. Sessions can contain more information.
Both are equally as safe, but to properly use cookies you'll have to spend a little bit more time.
If you're just starting with session management, just use sessions.
-edit-
Actually, technically cookies are more secure than sessions are. Since sessions are based on cookies they can only be as secure as cookies are, and almost always less secure than that. However, unless you have a very good implementation, sessions will be safer for you.
Depends on what kind of information you store in those cookies. But Sessions in general are more secure than cookies. Since cookies reside on the clients machine, while sessions are on your server.
If your server is already overloaded, better not use a database based session. Either use file based sessions (default per PHP) or the data you want to store is irrelevant, feel free to use cookies instead.

php using sessions or cookies for user authorization

I work for a php user authorization class and now I’m confused about sessions and cookies. I learned that wordpress doesn’t use sessions and I asked some php programmers if cookies are enough for security. Most of them said that: you have to use sessions for security, cookies can be modified.
However I use hash_hmac (md5) function with user’s ip address, password and cookie expiration date and noone can decode my encripted cookies code. Now I think cookies can be as safe as sessions.
Now I’m wondering that whether using cookies is faster than sessions, or not. I did a few tests and found that using cookies was faster than using sessions.
However, still I want to learn why wordpress doesn’t use sessions for authification process. Maybe I miss something, because many of my coder friends prefer both of them for authorization process. Would anyone let me know about this problem? Thanks.
I use hash_hmac (md5) function with user’s ip address, password and cookie expiration date and noone can decode my encripted cookies code
Are you simply signing the cookie data with an HMAC? It sounds like it. All an HMAC does is prove that a message has not been tampered with. Further, the IP address restriction is going to severely irritate users behind certain proxy servers.
Because the HMAC is just a signature, the cookie data can still be read and is entirely unencrypted, unless you have done so separately. If you have placed any data in that cookie that would permit a third party monitoring the connection access to the site as your user (such as, say, a simple un-salted hash of the user's password), then the HMAC is utterly useless.
If you want to put confidential information in a cookie, you should be using real encryption here, not just signing the data. (Read: Do both.)
If you are unable to perform actual encryption of the data, and the data is so risky that it has to be protected from prying eyes, then you shouldn't be sending it in a cookie. Or your entire site should be served over SSL. Or both.
But let's get to the meat of the issue:
If you're trying to simply identify if the current user is logged in, then sessions are a fantastic choice. It's hard to make them not work.
If you're trying to make a user login persist longer than the length of a session, then cookies are pretty much the most effective tool. However, you don't need to (read: should not) store any interesting information in the cookie. You can simply store a hash of some random data and identify it in the database as belonging to the specified user. Here is where your browser/IP restrictions can come into play. When the user isn't currently logged in, then check the cookie. If it's still valid, set their session data and regenerate the cookie with a new hash, invalidating the old one.
Be sure to set it up so the same user can be logged in to different machines without logging the others out. That's annoying as hell.
As for why Wordpress allegedly eschews sessions... well, Wordpress isn't the paragon of good design, and has made some huge compromises in the name of working pretty much anywhere. Shared hosting is hell.

Reason to use more cookies than just a session hash for authentication?

I usually hang out in a community that uses a bulletin board software.
I was looking at what this software saves as cookie in my browser.
As you can see it saves 6 cookies. Amongst them, what I consider to be important for authentification are:
ngisessionhash: hash of the current session
ngipassword: hash (not the plain password probably) of the password
ngiuserid: user's id
Those are my assumptions of course. I don't know for sure if ngilastactivity and ngilastvisit are used for the same reason.
My question is: why use all these cookie for authentication? My guess would be that maybe generating a session hash would be to easy so using the hashedpassword and userid adds security but what about cookie spoofing? I'm basically leaving on the client all fundamental informations.
What do you think?
UPDATE #1
The contents of these cookies are what I think they contains. I'm not sure about it.
Of course if call a cookie ngivbpassword and contains an hash, my guess is hashedpassword. Probably it could be password+salt.
My main concern is about these solution giving to much information when under a cookie spoofing attack.
UPDATE #2
This question doesn't want to criticize the way these specific software works but, thorugh these answers I want just to learn more about securing software in a web environment.
This happens because session and login cookies may have different lifecycles.
Imagine website with millions of users every day. The website won't store your session for a year just to log you back the next time you get back.
They use login cookies for that.
These cookies are also called Remember-Me cookies.
Sessions are not persistent. Cookies are.
Update #1: I haven't worked with vBullettin but it looks like the classical "Remember me" feature.
Update #2:
Yeah, it's a remember me feature, I'm
asking why they're doing it in that
way
Alright... How do you implement a "Remember me" feature? You obviously need to use cookies, I assume that's clear. Now, what do you store?
The naivest way is to store user and password in clear text and perform regular authentication. It's among the most insecure mechanisms you can use yet some sites actually do it that way.
Second slightly less naive way is to store a hash of the user and password and perform a modified version of the regular authentication. Is not as bad as the previous method but it still suffers from some issues; for instance, there's no effective way to disable or expire a saved cookie from the server.
Third way is to keep a database table with "remembered" sessions, identify each one with a long unique string and store such string in the cookie. The string can be random or calculated but, of course, randomness has the advantage that the string cannot be guessed even if you know the algorithm.
Further security can be accomplishes by storing dates, IP addresses and other piece of data in the server.
As I said, I know nothing about vBulleting but it seems they're using method 2 or method 3.
Update #3:
The contents of these cookies are what
I think they contains. I'm not sure
about it. Of course if call a cookie
ngivbpassword and contains an hash, my
guess is hashedpassword. Probably it
could be password+salt.[...] My main
concern is about these solution giving
to much information when under a
cookie spoofing attack.
A successfully cookie spoofing allows you to fully impersonate the user so you can just enter the control panel and enjoy the free buffet, thus making the cookie content irrelevant.
Whether they store a salted password or it's just a name it's something I don't know.
Here is a question, what are your concerns? Are you building some kind of authentication system?
I also think that having the user id and password in cookies can be a security issue.
is user id encoded or an integer?
Cookies should be as-small-as-they-can peace of information about who you are on the server.
Sessionhash, session_id or sid is unique ID of you (your session on the server). The rest of cookies can be easily hidden on the server side.
Holding password hash in cookies is a security issue. You should avoid that.
Last 4 cookies comes from google ads.
PS. Most bulletin boards are not so great software anyway.

PHP Sessions + Useragent with salt

It keeps running in my mind the last couple of days, but I read some articles about how to make your PHP sessions more secure. Almost all of these articles say that you need to save the useragent in the session WITH an additional salt. Something like this:
$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);
The salt would make it harder for an attacker to hijack or whatever the session. But WHY add a salt every time you would check it like this:
md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']) == $_SESSION [ 'fingerprint' ]
So WHY would a salt make it more secure, since the attacker still only needs the useragent (which is relativly a small set of different useragents) and the sessionid?
Probably something small I'm overlooking, but can't figure it out, drives me crazy haha
Thanks!
The reason that it's suggested to add a salt is simple. Generally, when you're creating this "fingerprint" - if you're using only one item of data, which has a limited dataset, then it makes it easier for an outside hacker to generate this, and hijack the session.
In your example above, yes, if the attacker has both the "fingerprint" and the User agent, then they will be able to hijack the session.
Adding a salt only makes it harder for an attacker to generate the fingerprint, it's a case of "if they have all but one piece of information, then the last piece of information is rendered useless)
I'd suggest that you add some more things in, for example, within vBulletin (a project I used to work on) the session ID hash (which is basically the same as the fingerprint) is generated with the following code.
define('SESSION_IDHASH', md5($_SERVER['HTTP_USER_AGENT'] . $this->fetch_substr_ip($registry->alt_ip))); // this should *never* change during a session
Also, a session hash is generated using
md5(uniqid(microtime(), true));
These are both checked when trying to identify the session
So, to hijack the session, the person would need to know the following
The time (exactly) on the server when the session was created
The users Browser agent string
The user's IP address
They would also have to spoof the IP address (or at least the first 2/3 octets) to be able to do this.
If they're actually at a point where they've managed to get the above information, then they're probably likely to be able to attack in other ways than just session hijacking.
vBulletin don't actually use a "salt" per se, but, in your above example, the salt is just adding a limited amount of entropy, it's always best to find as much entropy as possible.
For example, in something I'm currently writing in python, I generate a hash for usage with XSRF protection. The following is what I use.
self.key = sha1(
self.user.username +
self.user.password +
settings.SECRET_KEY +
strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
).hexdigest()
Which takes the user's username and password, the current time, and a preset salt to generate this. This would be hard for an attacker to generate due to the salt, and the time (though, do note that this is only made secure by the fact that it changes once it's used, with time, it wouldn't take much for someone to crack this for a particular user if it wasnt changing)
If I understand correctly, you want to prevent session hijacking by a remote attacker that guesses session IDs?
If this is not the case, then you are seriously out of your depth - an attacker that can snoop the traffic can also mimic the user agent, and an attacker that gains access to your session storage has you by the balls anyway.
If you store the user agent string to "lock" the session to the current user agent, then there is really no point in hashing it - string comparison on the full user agent string is faster (then hashing and then comparing) and not significantly more expensive in terms of storage.
I don't believe storing the user agent is providing enough differentiation - something better would be to generate a larger ID (with more bits) at session start time (maybe sha1 the current time stamp + user name + user agent + something), then store that in a cookie as well as in the session and match it up on each additional request. This doesn't change the attack vector much (you still need to guess some number), but its easy to significantly increase the number of bits that must be guess for a successful attack there by massively increasing the difficulty of the attack.
Update:
Something that other answers have mentioned in passing but is important to point about salting hashes: salting your hashes only makes sense if you expect an attacker to gain access to your stored hashes but not to your code, and then somehow uses it to leverage an attack.
This makes sense to passwords that are stored for a long time, usually in a well known location, and used by code that is hard to locate.
This does not make sense for your use case because:
The information is only viable while a session in progress (before timing out) this is rarely more than a few hours, after which - even if they got the storage and decoded everything - the session cannot be hijacked because it is over.
Usually if the attacker has timely access to your session storage, they have access to your plain text PHP code and can see your salt.
Unless you store your sessions in a completely unreasonable place (such as an S3 bucket), a hash stealing attack is mind boggingly less likely than a lot of other attacks that will be a lot more useful.
In short: don't waste your time writing session verification code - PHP built-in session management is already secure enough.
If you are on your own server, encrypting session variables is pointless, because they don't get out of the server. See Linead answer to What do I need to store in the php session when user logged in? for more info. If you are in a shared server, you may need to encrypt every session variables, besides the session ID, because they are stored on temp files readable by the same web server all your neighbours are using.
Anyway, if you are really worried about security, you are better with your own (virtual or not) server, so danger will only come from outside your server.
Some examples of risk to your sessions:
Your server sends the session ID in the URL, and your user follows a link to badguys.com They will get in server variables the referer (complete URL, including your session ID), the browser and the IP address of your user. If you are not checking IPs, or your user uses an open proxy, they only have to install same browser version, paste the URL, and they're done.
User go to a public PC, logins, and leave without closing his session (hey, he's human after all). Next guy in the row opens the browser, check history and finds an open session. Yuck.
So, some measures you can take, by my usual preference:
Don't send the session ID in the URL; enable session.use_only_cookies in PHP. Cons: User needs to enable cookies.
On dangerous actions (change password, make an order...), ask user for password again. You can do it periodically too. Cons: Annoying.
Timeout sessions fast. Cons: In most sites, this will force users to login often, annoying them.
Use SSL (only way to avoid 'man in the middle' attacks). Cons: Slow. Stupid browser messages. Need SSL on server.
Check the IP. Cons: Inneffective for visitors using a public proxy. Annoying for dynamic IPs.
Check the User Agent (browser). Cons: pretty much useless, UA is easy to get and trivial to imitate.
(I take for granted you have yet PHP configured for maximum security).
Some more extreme measures:
Maintain a permanent connection between server and browser, e.g. using a Java applet. No connection, no session. Cons: User needs Java, ActiveX or whatever you use. Session closes with browser (this can be good). Doesn't work on very slow connections. Higher load on server. You need to open ports, have a special server for the applet.
The same, but using asynchronous requests (e.g. AJAX) to refresh very frequently the session, and a very short timeout. Or refreshing a hidden IFRAME. Cons: User needs JavaScript. Doesn't work on very slow connections. Higher load on server.
The same, but reloading the whole page. Cons: User needs JavaScript. An automatic reload while you are reading a page is very annoying.
In some corner cases, you can forget about sessions and use Apache authentication instead. Simplest solution, but a lot of limitations.
As the fingerprint is stored on the server side, you don’t need to use a salted hash. A “normal” hash is enough to reduce the data.
I see one purpose in salting your fingerprint. If a bad guy gets hold of your session-db (god knows why) but not of your code he couldnt "guess" your fingerprinting method by trying the common user-agents against it.
I do that as well to partially protect from session impersonation attacks. You need to include the IP address as well.
Keep in mind that when the client's browser auto updates the user agent changes and you'll think that his session has been hijacked ;)
Bear in mind that if you do that you're forcing people to login again if they upgrade their browser. This can be OK but just make sure it's your intent.
Using the user's remote address is not without problems either. Many people use the same computer from different locations. Mobile devices, laptops being used at home and work, laptops being used at Wifi hotspots and so on. IMHO it's a bad idea to use IP address in such a way that a new IP address requires a login unless you're dealing with highly sensitive information such as online banking. Is that the case?
What are you concerned about? External attack? Or in a shared host situation that someone can read your session information?
If it's the latter, the solution is simple: just don't store anything sensitive in the session. Anything sensitive should be stored in the database.
In terms of creating a secret salt, you need to use something that isn't guessable. I would go for something like a random string that's created when the user is created. If necessary recreate it each time the session is invalidated.
As for what it would make it more secure, you said it yourself: there are limited user agent strings (less than a hundred will probably cover 99.99% of users). A salt simply increases the number of possibilities. That being said, if you use the same salt for all sessions then it's only a matter of time before it's found with brute force.
Okay, for example I'm using the following fictional code:
<?php
// The sessionid cookie is now a certain hash
if ( array_key_exists ( $_COOKIE [ 'sessionid' ] ) )
{
// Get the session from database
$db_sessid = $pdo -> getStuff ( 'session_database', $_COOKIE [ 'sessionid' ] );
if ( $db_sessid !== null && $db_sessid [ 'fingerprint' ] == sha1 ( 'SOMESALT' . $_SERVER [ 'HTTP_USER_AGENT' ] ) )
{
set_cookie ( ... ); // New sessionid and write also to DB
// User is now logged in, execute some user stuff
}
else
{
// Session doesn't exist, or the fingerprint does not match
}
}
Now the attacker only still needs the sessionid, which is in the cookie (sent along HTTP headers) and the useragent. So what's still the point of the additional salt?
Checking for IP's is also in my opinion not such a good option, some providers or proxy's change them every single request.
Thanks so far (-:
you allow the cookie after all the safegard parameters are met to just set a cookie if parameter are not met the cokkie will never be set nice but if the cookie has a parameter vissible what happens then. as well if conditions are never met the session willneevr be met.is that what you realy want. remeber a check met conditions give session and seession data way through the cookie
remember the cokkie sits on the clients browzer
regards stelios

Categories