Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

encrypted-client-sessions

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

encrypted-client-sessions

secure sessions stored in cookies

  • 1.0.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

build status

client-sessions is connect middleware that implements sessions in encrypted tamper-free cookies. For a complete introduction to encrypted client side sessions, refer to Francois Marier's blog post on the subject;

NOTE: It is not recommended using both this middleware and connect's built-in session middleware.

Installation

npm install client-sessions

Usage

Basic usage:

var sessions = require("client-sessions");
app.use(sessions({
  cookieName: 'mySession', // cookie name dictates the key name added to the request object
  secret: 'blargadeeblargblarg', // should be a large unguessable string
  duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms
  activeDuration: 1000 * 60 * 5 // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds
}));

app.use(function(req, res, next) {
  if (req.mySession.seenyou) {
    res.setHeader('X-Seen-You', 'true');
  } else {
    // setting a property will automatically cause a Set-Cookie response
    // to be sent
    req.mySession.seenyou = true;
    res.setHeader('X-Seen-You', 'false');
  }
});

You can control more specific cookie behavior during setup:

app.use(sessions({
  cookieName: 'mySession', // cookie name dictates the key name added to the request object
  secret: 'blargadeeblargblarg', // should be a large unguessable string
  duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms
  cookie: {
    path: '/api', // cookie will only be sent to requests under '/api'
    maxAge: 60000, // duration of the cookie in milliseconds, defaults to duration above
    ephemeral: false, // when true, cookie expires when the browser closes
    httpOnly: true, // when true, cookie is not accessible from javascript
    secure: false // when true, cookie will only be sent over SSL. use key 'secureProxy' instead if you handle SSL not in your node process
  }
}));

You can have multiple cookies:

// a 1 week session
app.use(sessions({
  cookieName: 'shopping_cart',
  secret: 'first secret',
  duration: 7 * 24 * 60 * 60 * 1000
}));

// a 2 hour encrypted session
app.use(sessions({
  cookieName: 'authenticated',
  secret: 'first secret',
  duration: 2 * 60 * 60 * 1000
}));

In this example, there's a 2 hour authentication session, but shopping carts persist for a week.

Finally, you can use requestKey to force the name where information can be accessed on the request object.

var sessions = require("client-sessions");
app.use(sessions({
  cookieName: 'mySession',
  requestKey: 'forcedSessionKey', // requestKey overrides cookieName for the key name added to the request object.
  secret: 'blargadeeblargblarg', // should be a large unguessable string or Buffer
  duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms
}));

app.use(function(req, res, next) {
  // requestKey forces the session information to be
  // accessed via forcedSessionKey
  if (req.forcedSessionKey.seenyou) {
    res.setHeader('X-Seen-You', 'true');
  }
  next();
});

Cryptography

A pair of encryption and signature keys are derived from the secret option via HMAC-SHA-256; the secret isn't used directly to encrypt or compute the MAC.

The key-derivation function, in pseudocode:

  encKey := HMAC-SHA-256(secret, 'cookiesession-encryption');
  sigKey := HMAC-SHA-256(secret, 'cookiesession-signature');

The AES-256-CBC cipher is used to encrypt the session contents, with an HMAC-SHA-256 authentication tag (via Encrypt-then-Mac composition). A random 128-bit Initialization Vector (IV) is generated for each encryption operation (this is the AES block size regardless of the key size). The CBC-mode input is padded with the usual PKCS#5 scheme.

In pseudocode, the encryption looks like the following, with || denoting concatenation. The createdAt and duration parameters are decimal strings.

  sessionText := cookieName || '=' || sessionJson
  iv := secureRandom(16 bytes)
  ciphertext := AES-256-CBC(encKey, iv, sessionText)
  payload := iv || '.' || ciphertext || '.' || createdAt || '.' || duration
  hmac := HMAC-SHA-256(sigKey, payload)
  cookie := base64url(iv) || '.' ||
    base64url(ciphertext) || '.' ||
    createdAt || '.' ||
    duration || '.' ||
    base64url(hmac)

For decryption, a constant-time equality operation is used to verify the HMAC output to avoid the plausible timing attack.

Advanced Cryptographic Options

The defaults are secure, but may not suit your requirements. Some example scenarios:

  • You want to use randomly-generated keys instead of using the key-derivation function used in this module.
  • AES-256 is overkill for the type of data you store in the session (e.g. not personally-identifiable or sensitive) and you'd like to trade-off decreasing the security level for CPU economy.
  • SHA-256 is maybe too weak for your application and you want to have more MAC security by using SHA-512, which grows the size of your cookies slightly.

If the defaults don't suit your needs, you can customize client-sessions. Beware: Changing keys and/or algorithms will make previously-generated Cookies invalid!

Configuring Keys

To configure independent encryption and signature (HMAC) keys:

app.use(sessions({
  encryptionKey: loadFromKeyStore('session-encryption-key'),
  signatureKey: loadFromKeyStore('session-signature-key'),
  // ... other options discussed above ...
}));
Configuring Algorithms

To specify custom algorithms and keys:

app.use(sessions({
  // use WEAKER-than-default encryption:
  encryptionAlgorithm: 'aes128',
  encryptionKey: loadFromKeyStore('session-encryption-key'),
  // use a SHORTER-than-default MAC:
  signatureAlgorithm: 'sha256-drop128',
  signatureKey: loadFromKeyStore('session-signature-key'),
  // ... other options discussed above ...
}));
Encryption Algorithms

Supported CBC-mode encryptionAlgorithms (and key length requirements):

CipherKey length
aes12816 bytes
aes19224 bytes
aes25632 bytes

These key lengths are exactly as required by the Advanced Encryption Standard.

Signature (HMAC) Algorithms

Supported HMAC signatureAlgorithms (and key length requirements):

HMACMinimum Key LengthMaximum Key Length
sha25632 bytes64 bytes
sha256-drop12832 bytes64 bytes
sha38448 bytes128 bytes
sha384-drop19248 bytes128 bytes
sha51264 bytes128 bytes
sha512-drop25664 bytes128 bytes

The HMAC key length requirements are derived from RFC 2104 section 3. The maximum key length can be exceeded, but it doesn't increase the security of the signature.

The -dropN algorithms discard the latter half of the HMAC output, which provides some additional protection against SHA2 length-extension attacks on top of HMAC. The same technique is used in the upcoming JSON Web Algorithms AES_CBC_HMAC_SHA2 authenticated cipher.

Generating Keys

One can easily generate both AES and HMAC-SHA2 keys via command line: openssl rand -base64 32 for a 32-byte (256-bit) key. It's easy to then parse that output into a Buffer:

function loadKeyFromStore(name) {
  var text = myConfig.keys[name];
  return Buffer.from(text, 'base64');
}
Key Constraints

If you specify encryptionKey or signatureKey, you must supply the other as well.

The following constraints must be met or an Error will be thrown:

  1. both keys must be Buffers.
  2. the keys must be different.
  3. the encryption key are exactly the length required (see above).
  4. the signature key has at least the length required (see above).

Based on the above, please note that if you specify a secret and a signatureAlgorithm, you need to use sha256 or sha256-drop128.

License

This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

FAQs

Package last updated on 14 Apr 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc