Should session ID cookie be signed? - node.js

I was using the Node library https://github.com/expressjs/session and noticed that it requires a secret to be specified for signing the session ID cookie.
If just the session ID is being stored in the cookie, and not any data, what is the use in signing the cookie?
My reasoning is that if someone wanted to modify a session ID cookie, then that's fine if the session ID sufficiently long to prevent brute force attacks. Am I missing something?

I questioned this as well and the only answers I could think of were,
a) If someone (for no good reason?) changes the default session ID
generation to a non-cryptographically random session ID, signing it
helps prevent attackers generating valid session IDs.
b) Reduce round trips to the session store by validating the session
ID using the signature/HMAC. (I can only imagine this being a problem
for DoS attacks).
Both seem like valid reasons though using good session caching would negate the need for b) and assuming your library's users are daft enough to change the default session ID generation, it seems a bit much to safe-guard against their own stupidity when the majority of users would just use the default generation algorithm.

If you store just id of session there is not reason to encrypt it. You are right.
You need to encrypt if you store some session data inside cookie, not only id.
This will prevent users of changing session data.

A session_id cookie is anything (number or alphanumeric) which identifies a client to a server, which in turns stores (usually temporary) data on the server accessed through this session_id/key.
The point is, if the cookie is going to be passed forth and back over HTTP, it doesn't matter whether you have "signed" it or not. Any man-in-the-middle could get your "signed/encrypted session_id" and make further requests pretending be the proper user. And I mean, this attacker doesn't have to care which information is inside the encrypted data, he could pass the exactly same signed/encrypted data, and the server couldn't figure out if it comes really from the right user.
In cases like these, you have to figure out if the privacy is important, if so, don't think too much, you got have to use HTTPS. If you understand it is not so important, don't waste your "processing time" signing/encrypting and decrypting your session id.
This answer is valid only for signed session_id.

I believe the reason it is signed is so that it is not easily guessable. For instance if someone decided to use integers as session id's, you could easily impersonate another user's session by trying multiple numbers. I believe that the signing makes it so that changing your session id value client side will not be valid (that is it prevents tampering).

Related

what if I have session id of some user? [duplicate]

I'm not exactly sure how the $_SESSION work in PHP. I assume it is a cookie on the browser matched up with an unique key on the server. Is it possible to fake that and by pass logins that only uses sessions to identify the user.
If $_SESSION doesn't work like that, can someone potentially fake cookies and bypass logins?
Yes.
The only thing identifying a user is a pseudo-random value being sent along with each request.
If an attacker can guess the right values to send, he can pose as somebody else.
There are different ways to make this harder:
make session ids longer (more entropy, harder to guess)
check additional information like the user agent (essentially more entropy)
obviously: use a good random number generator
expire sessions sooner to give a smaller set of valid session ids at any one time
renew session ids often, even for valid ids
use SSL to encrypt all communication to avoid outright cookie hijacking
Sessions in PHP by default store the data in a file on the server (/tmp/) and store an identifier cookie usually PHPSESSID (it will be a hexadecimal number, e.g. f00f8c6e83cf2b9fe5a30878de8c3741).
If you have someone else's identifier, then you could in theory use their session.
However, most sites check to ensure the user agent is consistent and also regenerate the session identiifer every handful of requests, to mitigate this.
As for guessing a session, it's possible, but extremely unlikely. It'd be easier to guess credit card numbers (smaller pool of characters (0-9 over 0-9a-f) and a checksum to validate it). Though of course you'd also need the expiry and security code.
Properly implemented, session ids are very long and random enough to make guessing unfeasible (though if you were able to guess a particular user's session id then yes you would be acting as that user). However you can sniff and hijack sessions -- this is what firesheep does: http://en.wikipedia.org/wiki/Firesheep

Session fixation with session in cookies

There are a lot of questions and answers about session fixation on StackOverflow, however, I am still confused about one thing. People often suggest that storing session in cookies is not enough to overcome the session fixation issue and you should rotate the session id after login. I can imagine that if you only use the session id to identify a user, you may still be vulnerable to an attack. However, I would like to ask about one specific case.
Let's assume that you use a signed cookie to store the whole session. On login you put into the cookie an id identifying the user. After logout, you delete the id. You do not change the session id, but as you change the session itself and you sign it, I cannot see any attack scenario taking advantage of this design. Is session fixation still an issue and, hence, is session id rotation still necessary in this case? If yes, can you provide an attack that could be used? Thank you.
The basics of Session Fixation is that it’s possible for an attacker to make the victim use a session that the attacker has access to. This is generally done by inducing the victim to use a certain session ID that is known to the attacker and doesn’t change after authentication.
Now what you’ve described doesn’t sound like a session identifier but rather a simple client-side data storage of user authentication data.
But nonetheless, if you make the cookie data dependent on data that again depends on the authenticated user which additionally is signed by the server, it certainly will change after authentication and won’t be known to the attacker. Then the security of that scheme depends on its actual implementation.

HTTP Remember me authentication

I'm trying to write a simple HTTP remember me authentication system for users.
My users could be represented as such
{
"email" : "foo#bar.com",
"password" : "8EC41F4334C1B9615F930270A4F8BBC2F5A2FCD3" // sha1 hash of password
}
So my idea is that I need to create a cookie, with indefinite (really long) expiration time, that will hold some type of information to enable me to fetch the user from the database, therefore logging the user in.
My first idea was to just simply store the email:password string as a cookie. I thought this would be good since nobody else can really generate that type of information other than the user itself, and I could retrieve the user quite easily by simply comparing the username and password based on what's in the database.
However then I thought this wasn't really good. It turns the password digest into, effectively, a second password that's stored in the clear and passed over the wire in every request.
So then I thought maybe I could generate a signature each time the user logs in, which would basically be a random hash that is stored directly in the user object in the database.
The user logs in, it generates this signature that is stored, and the cookie holds this signature. Whenever you access the website, the site checks which user has that particular signature and logs the user in. Logging out will effectively erase the cookie, and new logins will generate a new random signature.
Does this approach take into account any other vulnerabilities?
I know, I should probably use a library already made for this, but this is just simply an exercise in web-security.
This is essentially what most sites do when you log in. Yes, the cookie should hold a unique identifier for the user's "session". The cookie should be essentially random. Up to you whether to make it persistent across browser sessions.
Along with the cookie in your authentication DB, also store a timestamp of when the entry was created. Cookies older than N seconds should be considered invalid (set N to your taste). You can reset the timestamp each time the cookie is used so that idle sessions time out.
Note that the same user may want to have multiple sessions (do you ever log in to your Email account from both home and work?), so the concept here really is "session", not user.
Vulnerability point-of-view both are same! Cookie stealing and related mechanisms however browsers are smart enough now so you shouldn't worry about that.
Second approach is good in terms of privacy as well since it does not includes email address in the cookie. And it seems much more similar to like storing the sessionID which in your case you are generating a random hash and storing it in DB.
But i think it would be more wiser to use the first approach; you can add another layer to the digest and encrypt it with your some algo or private key; to be on safer side.

What is the session's "secret" option?

I don't know anything about cryptography. I'm wondering what the session secret is.
I see code like this:
app.use(express.session({
store: mongoStore({
url: app.set('db-uri')
}),
secret: 'topsecret'
}));
What is the secret and should I change it?
Yes, you should change it. A session secret in connect is simply used to compute the hash. Without the string, access to the session would essentially be "denied". Take a look at the connect docs, that should help a little bit.
The secret is used to hash the session with HMAC:
https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js#L256
The session is then protected against session hijacking by checking the fingerprint against the hash with the secret:
https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js#L281-L287
Motivation for this answer
The other answers address "Should I change it?" and provide a surface-level explanation on "What is it?" As someone who just started using express-session, I was curious and in my reading found much disagreement over whether having a secret like this is valuable and how much.
Many people discussing this topic seem to be security novices like myself. However, I came across this answer with a comprehensive explanation of the intended effect of the secret and some of the possibilities. You should read the whole answer, but I will try to summarize.
What does the secret protect against?
The type of attack in question here is session hijacking. Typically, this involves the attacker acquiring the session ID of a valid user, thereby being able to emulate that user's session and allowing the attacker to access information or act on the victim's behalf.
How can you protect against session hijacking?
A good start is to use a session ID that is suffienciently long and random, as it inhibits an attacker's ability to guess the ID. As noted by the other answer's author:
It is also critical that session ids are not generated using a predictable algorithm such as a counter because if such logic exists, the attacker is no longer guessing but generating session ids.
As an example: if an attacker finds out that your session IDs are sequential (e.g. 1, 2, 3), then if they discover a session ID of 2 then they can reasonably assume 1 and 3 are session IDs as well.
What does express-session's secret do?
The Express session middleware...calculates a hash over the combination of the session id and a secret. Since calculating the hash requires possession of the secret, an attacker will not be able to generate valid session ids without guessing the secret (or just trying to guess the hash).
So the secret is used to create a hash that is long and random. If the session ID is already sufficiently long and random, then using a secret in this manner is largely redundant. As other users have pointed out, at the end of the day, the attacker is just guessing one long and random instead of another.
But don't be so quick to dismiss the use of hashing!
express-session is a public package
An important feature of the Express session middleware is its support for user-generated session ids. This allows developer to deploy the middleware in an existing environment where session ids are generated by an existing entity which might reside on a completely different platform. Without adding a hash to the user-provided session ids, the burden of building a secure system moves from the expert (the module author) to the user (which is likely to be a security novice). Applying a hash is a much better approach than forcing an internal session id generator.
If an inexperienced user instead defines their own insecure session ID generator (e.g. say, something sequential as discussed above), hashing it will ameliorate that security flaw.
As the author notes elsewhere:
Also, this is a generic module assuming as it's core requirement a wide range of users. It absolutely has to assume that some people will use it poorly (e.g. increment ids) and accommodate that. This is also common practice when building modules for a wide audience.
Don't put all your eggs in one basket
Hashing using a secret is one layer of security, and can help cover flaws in other layers. What if your random session ID generator has a bug that can be exploited? What if you accidentally use RNG.pseudoRandomNumber() instead of RNG.strongRandomNumber() when coding? What if one of your dependencies breaks or is compromised? Once again, hashing helps patch those flaws.
There are other benefits
You can detect the difference between expired/unallocated IDs and invalid (maliciously generated) IDs:
By including an integrity component in the session id (via a hash or signature), the server can immediately tell the difference between an expired session, an unallocated session id, and an invalid session. Even if you just log invalid authentication attempts (and you should), you would want to log an expired session differently than an invalid one.
You can build a tamper-resistant timestamp into the ID:
While cookies come with an expiration policy, there is no way to ensure it is actually obeyed. (...) A common best practice is to include a timestamp in every credential issued, which can be as simple as adding a timestamp suffix to the randomly generate session id. However, in order to rely on this timestamp, we must be able to verify it was not tempered with and the way to accomplish that is with a hash or signature. (...) Adding a timestamp to the session id allows the server to quickly handle expired sessions without having to make an expensive database lookup.
You can immediately invalidate many IDs if something goes wrong:
Because generating a hash or signature requires a server-side secret or key, replacing the secret will immediately cause all session ids to fail validation. By using different secrets for different types of session ids, entire classes of sessions can be segregated and managed. Without such a mechanism, the application itself has to make a computed decision about the state of each session or perform mass database updates.
In Conclusion
The having a secret (and using it to hash) provides many benefits:
It protects users from themselves
It adds an extra layer of defense
(With a custom session ID generator) It allows detecting malicious behavior
(With a custom session ID generator) It allows bundling a timestamp into the ID
It provides a kill switch
And once again, I would like to credit this answer for everything in this post. I am just a curious onlooker!

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.

Resources