Skip to content

Instantly share code, notes, and snippets.

@HallM
Created March 28, 2016 21:29
Show Gist options
  • Save HallM/bb4ffacfd15763b2a5a2 to your computer and use it in GitHub Desktop.
Save HallM/bb4ffacfd15763b2a5a2 to your computer and use it in GitHub Desktop.

Session State Management & Security

Intro

  • This talk is focused on the concepts, not the commonly used competing strategies.
  • Knowing the details helps fine tune the implementation for certain scenarios depending your requirements

JWT vs Session IDs:

Sessions IDs

  • by session IDs, I refer to storing an token client side that points to a record in a session store
  • this token is just a unique identifier, can look like anything. Just the ticket to get to the data
  • commonly knocked as "not scalable" as many by default use RAM to store records
  • session records are not required to be in memory, can be in data store (Redis, Mongo, Postgres, anything)
  • storing sensitive information is session records out of the client is not necessarily more secure
    • how secure is the session storage? is it a "one-stop-shop" for private information? still sending data out
  • improper generation of session IDs could lead to predictability, a major security concern
    • while cookie-signing helps prevent forged session-cookies, the general consensus is to use cryptographically secure random numbers for session IDs.
  • session fixation is a common implementation issue. Must remember to destroy+create in some events such as:
    • login
    • logout
    • password change
  • must have protection to prevent session IDs from being stolen such as through XSS vulnerabilities
  • easy to list or invalidate sessions using the record

JSON Web Tokens (JWTs)

  • JWTs store some information on the client side with a signature to prevent tampering

  • commonly believed more scalable as the session record can be put 100% on the client

  • what if you need to invalidate a session?

    • scenario: user logs out. Without invalidation, their token is still valid and could be used.

    • scenario: user has account hijacked. User regains control through password reset or Customer Support the hijacker's JWT would still be valid unless the server has a way to revoke tokens

    • scenario: user's device is stolen. revoking the token would prevent unauthorized access to the account

  • the only way to invalidate is to track what tokens are valid in some data storage (RAM, Redis, Mongo, etc)

  • in the end, are JWTs any more scalable than session IDs?

    • JWTs do allow storage of information which may prevent an extra DB lookup.

      Be careful on what is stored. For example, storing the User's Permissions in the JWT would require an invalidation when demoting a user in order to guarantee the new permissions take effect immediately. Not storing the permissions in the JWT allows the token to remain valid and the user session to continue. You may desire the invalidation cycle for a security requirement, so this isn't a concern.

      Also, avoid storing sensitive information in the JWT. Even with HTTPS and encryption, if you do not absolutely need to store it client side, stick with leaving it server side.

    • Confirming validity of the token may be a slightly faster "does this record exist in the DB" compared to a full record retrieval. Validate across multiple fields (who, when). Avoid storing the signature in the DB and definitely never ever use a stored signature for validation. Always compute yourself.

  • JWT validation may feel like one trades data storage access for more CPU to compute and validate signatures

  • while true, session IDs stored in cookies are generally signed and validated as well. JWTs are already signed

  • JWTs can still lead to predictability without a nonce or timestamp

  • timestamp is predictable. some consider it good enough with the signature.

  • high security requirements may warrant a cryptographically secure randomly generated nonce.

  • still just as vulnerable to being stolen such as through XSS vulnerabilities

Are there others?

  • More than likely. I consider these two to be the current top competing session identification methods.

Which to use?

  • Both are good, both must be used wisely.
  • Using session IDs is so common and has been for so long. We are used to it, we solved many pitfalls already
  • JWTs are new to the game and may be more complex, but you might get some performance boosts
  • How much gain? depends on how strict you get with JWTs
  • In many cases, use what you are comfortable with
  • If you aren't comfortable, you may end up exposing security vulnerabilities

Cookies vs Local Storage

  • No matter which you decide to store client-side, you still have to pick how to store it.
  • While session IDs often go with cookies and JWTs often go with local storage, they are not exclusive. An oath token is a form of session ID and may be stored in local storage.

Cookies

  • Cookies are basically files that store data (max 4k bytes in many cases, watch out for JWT sizes)
  • Cookies are transmitted with every request without extra effort
  • pretty much the de-facto place for session IDs
  • XSS protection can easily be enabled for cookies by using the HTTP-only flag
  • XSS is not just limited to code we write
    • Do you pull it CDN versions of libraries?
    • Are you certain the libraries you use don't pull in anything external (Google Analytics)
    • Can you be certain these external libraries will never be compromised?
  • vulnerable to CSRF as cookies are transmitted even during requests outside of your website
    • scenario: a website could make a fake request to transfer all your funds from your bank. they don't need to know you, since your cookies are transmitted for them.
  • CSRF mitigation techniques are well known, though variation exists in implementation details.
  • CSRF is not about preventing a hacker from hijacking a session or using known values to send a request. it's preventing a drive-by situation where an automated request is forged
  • the general recommendation is the Synchronizer Token Pattern
  • limiting CORS helps browsers that support the Origin header by preventing external XHR, not required

(describe CSRF and the STPattern)

  • easy to get CSRF wrong, especially with front-end heavy apps:

    • How do you get the CSRF token to the browser?
      • full page load with a form-field set to the token
      • exposing an API to get the CSRF token? Hacker's website could use the same API
      • cookie? that's what caused the problem in the first place! only use cookie for XHR or JS set form field
    • Keep the CSRF token separate from session identification, therefore do not store CSRF in a JWT
      • why not??? (elaborate)
    • Relying on Referer (yes, incorrectly spelled) or Origin? Not all browsers support these
    • How long do CSRF tokens live? Per-session? Per-user? 5 minutes? Usability vs security tradeoffs
    • What about XSS protection of CSRF token?
      • Much like protecting your home from robbers, you can never have 100% security. You just make it as difficult as possible to deter them. Pulling off an XSS and then followed up by a CSRF attack is extremely difficult. Odds are, if they could get that level of XSS, they probably don't need a CSRF. Just do it right then.
  • CSRF protection can only go so far. For the ultra sensitive things, ask the user to re-enter password Though, you should always ask for a user's password for these things no matter the session storage Shared computer, someone left their PC logged in and walked away, stolen session ID or JWT, and more

Local Storage

  • Local Storage (and Session Storage) is a fairly new way of storing application data
  • Supported on all current major browsers (even IE8 and up)
  • Limits on local storage are much higher than cookies
  • Much like cookies, the storage can only be accessed within the same site
  • Unlike cookies, the HTTP-only and secure-only protections do not exist
  • Local Storage is vulnerable to XSS attacks, you focus on protecting from XSS attacks you should be anyway, but now your sessions could be stolen and used later (you can revoke JWTs right?)
  • It is not vulnerable to CSRF attacks. The token must be read by JavaScript, attached as a header in XHR
  • Local Storage can only be sent by XHR or some other API call, so browser page loads do not have state This can lead to a situation where the server responds with a bootstrap page that must check for session, make an API request with the token, then finish rendering client side.
  • Generally, the token is sent over an HTTP header such as "Authorization: Bearer TOKEN"
  • Never include in URL query parameters, these may be cached or become accessible in unwanted situations
  • POST bodies? possible, but you're better off with the HTTP header:
    • an attacker could create a form that does not use XHR and submit a stolen token. Headers can only be set by XHR. XHR will also include the Origin if the browser supports it. You don't use * for CORS, right?

Which to use?

  • Focus on your requirements and decide based on that
  • Both have vulnerabilities from different sources
  • Are you server-side heavy? Need to know state to render a page? Cookies (no complex bootstrap pages)
    • Can you use Local Storage? yes. It's just more complicated. More complications can lead to more bugs.
  • Using a "Single Load App" with no, or minimal well controlled, external js? Local Storage is an option
  • Does this SPA talk to various microservices exposed as REST APIs? Don't want to fight cookie domains/paths for all these microservices? Local Storage can simplify storing the token for all these XHR requests
  • Cookies have been used for so long, the mitigation patterns are very well known
  • Local Storage is newer, maybe we haven't figured out all the ways to exploit But, we are still finding new ways to exploit cookies, so it's bound to happen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment