Hacker News new | past | comments | ask | show | jobs | submit login

This seems to be a common practice, storing UserIDs, Usernames, etc. in cookies rather than a unique SessionID that can be used to look those things up (and will expire). I'm curious as to where people are getting the idea to build things that way.

Because it never would have occurred to me to do so. Or rather, had it occurred, it would have immediately begged the question of "what happens when the user monkeys with their cookie". Surely everybody else thinks the same way.

If so, how do we end up with this? Are there really "Teach yourself in 21 Days" books that have examples with this pattern that people are following?

Or does everybody just assume that they're going to be Facebook with 4000 servers and no way to quickly generate or store or manage or look up those keys for millions of simultaneous users, and that it's worth the tradeoff?




A couple of rambling thoughts on how we get here:

1. Lack of experience. Most web devs that's I've met have never even heard of using expiring session tokens in a cookie. (imho) It's been my experience that most javascript guys can be relatively young as it's the new teaching language (sorry python). They spend most of their time learning react/redux/moxd/angularjs2/vue and just haven't been exposed to security practices like expiring session tokens in cookie. It's not their fault, it's just that we don't know, what we don't know. Not realizing that this practice has been around for almost 20 years, the developer invented a new way of logging in using cookies.

2. Most people don't take security seriously. I recently had a conversation with a dev that was being a cool kid by using JWT bearer tokens. He was putting admin=true inside the bearer token and signing it. I asked him what would happen if I stolen his token. Would I become the admin? The answer appeared to be yes, the software would read the bearer token, inject admin=true into your session, and give you admin rights on the webserver. However, he explained the expiration of the JWT token was 1 hour. So I steal and use your token I only have 1 hour to become admin on your site?, I asked. Apparently he felt that was good enough.

3. Security is expected to be provided by the framework. XSS, CSRF, SQL injection - don't worry we're using Django. That seems to be the expectation of most people. You don't need to know about security, because the framework handles that. The problem is that this only gets you so far, there are things that live outside of the scope of the framework that you probably should know about, but don't. (I guess storing the user's password in a cookie would be one of those)


I don't see how number two is a security issue. Maybe I'm misunderstanding or maybe I'm ignorant. If I steal an admin's session token, it follows that I get to be an admin. How does a JWT with admin=true exacerbate this issue, or how would any other type of session token mitigate it?


Well, the comment you're replying to only described the issue as "being a cool kid by using JWT bearer tokens", which isn't enough information to accurately describe what's happening. One can only guess...

A JWT is just a base64 encoded JSON object that has a signature. You can pass one to any base64decode() function to see the actual data, so the important part is checking the signature to see whether it's been tampered with.

But the whole "admin=true" part, while it doesn't sound like best practice, isn't inherently less secure than using the JWT notation for scopes. "admin=true" might as well be "scope=admin" so the person criticizing the "cool kid" doesn't seem to understand JWT usage themselves.

What's important is where you sign and verify a JWT: Signing means using a secret key, which means actually having a secret key stored, which means that it has to happen server-side.

Proper JWT usage means that both the data creation/signing and data reading/verifying are always happening on the server, and you've got to trust the security of your servers, since they have the ability to read your shared secret key.

So to be secure, you shouldn't really send the JWT to an insecure client like a web browser at all. Since anyone can read a JWT, you're unnecessarily leaking information about the inner workings of the app, just giving hackers important info like the variable names you're checking for.

Instead, the best move is to use key/value storage for hashing your JWT into garbage and sending that over to the browser. When the user performs an action, they'll send the nonsense key and the server will retrieve the actual JWT and verify/perform the actual request handling.

Of course, this just takes the conversation back to session handling. There are various ways to mitigate the risk of someone stealing another user's session data and using it to impersonate the user, but those aren't unique to JWT.

Anyway, the comment above doesn't give enough detail about what the "cool kid" was doing in order to determine whether it was bad security or not. Sounds like either a lazy description of the actual scenario, or a poor understanding of JWTs.


It is an extra vuln. if the JWT only has the role=admin K/V, and no expiration value.

A jwt that is only valid for a certain time is no less secure than a session id, as long as you verify the signature correctly.


Curious about the 2. JWTs are signed via a secret key right? Couldn't the backend verify the signature and reject the token. I am pretty confident most JWT implementation does that automatically.

The dude just didn't think about that or looked into how JWTs work. Which I believe is even worse :<


I think you're thinking of a different attack vector, namely, forging a new JWT.

Whereas the parent poster said "what would happen if I stolen his token" (for example, via XSS). So in that case, it's a legit token in the hands of a bad actor, and the signature would be still be valid as far as the backend could tell.


Your #2 explanation is vague. Are you saying that the system had no server-side storage of whether a given user had admin rights or not?

In #1 you mention "security practices like expiring session tokens in cookie" and then go on in #2 to say that the exact same thing isn't good enough. You do know that the T in JWT stands for "token", right?

Are you sending raw JWTs straight to the browser? Why? That's the big problem, not setting "admin=true" inside of a JWT. The data in a JWT is a claim that's meant to be verified by signing. It's no more and no less.

If you want to describe the OAuth implementation or something more substantial than a "cool kid" then it might be more illuminating, but you don't give any context.


>It's been my experience that most javascript guys can be relatively young

I really don't understand how these people make it through the magic 'must have 5 years experience' marker and just don't know proper security practices. It seems like people just lie on that.


They lie because the constraint is a lie. The years of experience requirement is entirely made up by a lazy hiring manager, and is just a poor proxy for "has this person tried and failed and learned enough from their mistakes to make well-reasoned decisions about future things without my constant oversight and input."


About #3, storing user authentication is one of the best examples¹ of things you should rely on your framework for. It's not as simple as it looks like, what is considered "safe" changes suddenly, and it is very standardized.

And it's well within the scope of Django.

The blame is almost completely in #1 and #2.

1 - And, yes, protection against XSS, CSRF, and SQL injection are other great examples.


>> Are there really "Teach yourself in 21 Days" books that have examples with this pattern that people are following?

Yes. From Learning PHP, MySQL, Javascript, CSS & HTML5, Third Edition, from O'Reilly publishing:

So, to create a cookie with the name username and the value Hannah that is accessible across the entire web server on the current domain, and will be removed from the browser’s cache in seven days, use the following:

    setcookie('username', 'Hannah', time() + 60 * 60 * 24 * , '/');
And that was published in 2014, not 2004.


A username is different from a password. There can often be legitimate or at least semi-legitimate reasons to do this.

I dunno everyone has to learn how to use cookies if they are building web apps.

Password is obviously just bad.


Everyone, really?

I've been building webapps since forever and I've never cookies directly in Javascript like that and I can't, personally, think of a use case where I would do that.

I've only used cookies that store a session id and I store everything in the session. The session id cookies are handled entirely by the servlet container.

I don't believe I'm doing it horribly wrong.


What you stated is pretty normal seeming to me, so no, not "everyone". But I think web developers still need to know what a cookie is and how to use it, even if you dont use them often. They can provide a better user experience remembering some aspects of a user or their session long after it has expired. Many sites have semi-authenticated states where you may not want to hold user data, but still remember some details about their session.


User IDs and usernames, are generally public information, so I do not see the problem with storing that in a cookie, as long as you authenticate it (e.g. using a MAC, and you might want to include a timestamp and a version number). It does however sacrifice server-side control of sessions.


To answer your question about monkeying: Sign the cookie! We sign session cookies with HMAC, and reset the session if it doesn't match. Doesn't handle replay attacks, but you at least know that you're getting back the same data that you gave the client.


Doesn't handle replay attacks...

This is why we have CSRF tokens, right? Orthogonal to session cookies, but when used together they avoid this vuln.


Does signing the cookie with secondary information such IP or UA help? I know they can both be spoofed, but it's an extra layer...


Signing the cookie with IP would break the site for everyone with changing IPs, e.g. mobile users on cellular networks. Web site sessions should persist across IPs.


We were doing that previously in our homegrown framework. Session would include id, username, and an expiration timestamp along with a salted hash of that data to confirm. We've since moved away from it (and the entire homegrown framework, actually) because we realized it didn't make anything easier, but we've never had an issues with that data being in the session (it was all publicly available regardless).

In the end, though, it is probably best to err on the safe side and only expose a salted and hashed session ID via cookies, and then doing a server side lookup to get the necessary data (which you would need to do regardless)


It seems we revisit this topic or a branch of it often enough that it's almost becoming a meme.

Here is a 2-page, 7.4K security checklist. If you verify and check each box, your application won't be bulletproof (it is software and you have 3rd party libraries), but it will be close to air tight. --Disclaimer: I have nothing to do with this security checklist or its authors, except appreciation and respect.

Security Guide For Developers - Latest: https://github.com/FallibleInc/security-guide-for-developers...

--Donald


It's literally used on hundreds of websites. I'm sure there is a developer out there right now going "How does McDonald's do this?"


I don't think everyone assumes they're going to be Facebook, but they probably do assume (correctly not my opinion) that scaling session management up is a painful, and are doing their best to avoid it.

Consider it a teaching moment and show folks how simple it is to store all your session-like stuff in cookies, along with a timeout and a version hashed with the server's secret.


It's something i've steered away from, or I would encrypt the id before saving it in the session. I don't exactly recall where I picked it up, but i know i've seen it in example tutorials in books with Rails apps.


FWIW, all session information (`session[:user_id]`) is stored in an encrypted cookie starting with Rails 4.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: