Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#178: Feature request to encrypt session data stored in cookies #182

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

jmitchell38488
Copy link
Contributor

@jmitchell38488 jmitchell38488 commented Aug 19, 2019

This references issue: #178.

When session data is stored in the cookie, it isn't cryptographically encrypted, and is therefore unsecure. The existing encode and decode functions simply pass the JSON object through to be stringified and converted to base64, and back again.

This pull request adds functionality to use crypto-supported algorithms to encrypt their session data, to safely store in a cookie.

The IV length and key length checks are handled by crypto, while validation exists within the feature to verify correctly formatted encryption options, encrypted string, and data.

A user can extend the session.opts object and define what algorithm they want to use, the initialization vector length, and the key, and set the flag useCrypto to true, and the library will handle the rest.

eg.

const encrypt = require('./lib/encrypt');
const crypto = require('crypto');

const options = {
  useCrypt: true,
  ivlen: 16,
  algo: 'aes-256-gcm',
  secret: crypto.randomBytes(32);
};

const data = {
  message: 'hello, world!',
};

const encrypted = encrypt.encryptData(data, options);
console.log(encrypted);
console.log(encrypt.decryptData(encrypted, options));

A user can also use these same settings when initialising the session instance in App:

const crypto = require('crypto');
const Koa = require('koa');
const app = new Koa();
const session = require('./index');

const options = {
  useCrypt: true,
  ivlen: 16,
  algo: 'aes-256-gcm',
  secret: crypto.randomBytes(32),
};

let views = 0;
app.keys = [ 'a', 'b' ];
app.use(session(options, app));
app.use(async ctx => {
  views++;
  ctx.session.views = views;
  ctx.session.message = 'hello, world! Views: ' + ctx.session.views;
  ctx.body = ctx.session.message;
});

app.listen(3000);

Output:

curl -v http://localhost:3000/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Content-Length: 22
< Set-Cookie: koa:sess=MjNhMDQ2N2VlMmVjOTc1ZjAwNzUyNjUyYTFjMTBjNDUuNjIwNGFlMjMyNTk2NDVlYjdhZjAzOTIzYjc5NGU3ZGIuMmQ1ZmI3MjMyMzk1MTA4ODg2MzQyNzdiZDNhNThhZGRhYzQzYTVlZjBkYmQ2Nzg0Njg0ZmNhNjllYWVlMTMxYjEyZjdmYzUxYjE3NzY2ZDU3MmIxMTE1MmU1NmNkYjI4MDE4NGE3NWJiZTFiYTYwY2Q1NTM4ZDBlM2RlYzMwMjFmZTdmMGI2NDBkZjA2MjI4MTY1NjViZTJkZTI1ZDU3ZmJmMmIyNjhhM2NlYmYwNjliZA==; path=/; httponly
< Set-Cookie: koa:sess.sig=zGGX31V-b5u_ioX0EP_YsfVARzk; path=/; httponly
< Date: Mon, 19 Aug 2019 07:27:51 GMT
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
hello, world! Views: 1

I have also updated index.js to include default values for the accepted options. This ensures that values are always set, and that it provides a degree of information to the developer about what options there are.

const defaults = {
  key: 'koa:sess',
  overwrite: true,
  httpOnly: true,
  signed: true,
  autoCommit: true,
  maxAge: null,
  useCrypt: false,
};
...
function formatOpts(opts) {
  opts = Object.assign({}, defaults, opts || {});
  ...
}

TODO
Add the following test cases

  • formatOpts
  • defining the encode and decode functions
  • the encrypt file
  • cookies with crypto encoded data
    Also:
  • Add performance stats

…ession data stored in the cookie. The encrypted data, along with the IV and AuthTag (where applicable) are encoded as a base64 string in the cookie data. A RangeError is thrown if the base64 encoded string exceeds the cookie max length of 4093 bytes, while the module exposes the 'encryptData' and 'decryptData' functions.
…object. This is used to pass the user defined options through to the crypto encode/decode functions
…are used as per the initialisation steps. Updated the 'formatOpts' function to use the defaults values, and added 'useCrypt' as an option, to cryptographically encode/decode the session data stored in the cookie. This uses the existing session storage in the cookie functionality, and only encodes the data when session store is set to cookie.
@coveralls
Copy link

Coverage Status

Coverage decreased (-61.3%) to 38.71% when pulling e2d86a7 on jmitchell38488:gh-178-encrypt-cookie into 10bb122 on koajs:master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage decreased (-61.3%) to 38.71% when pulling e2d86a7 on jmitchell38488:gh-178-encrypt-cookie into 10bb122 on koajs:master.

@dead-horse
Copy link
Member

I'd recommend https://github.com/nicokaiser/koa-encrypted-session for now, or you can write your own wrapper to use specific encrypt/decrypt methods.

@jmitchell38488
Copy link
Contributor Author

@dead-horse that one prescribes the algo, rather than letting you set it. I've set this one up with more flex around the algo you can pick, and whether you want to enable it.

@jmitchell38488
Copy link
Contributor Author

@dead-horse is this something that would be merged into the code base?

@rnd256
Copy link

rnd256 commented Aug 19, 2019

It looks like this would be one way to resolve #181, which may otherwise be a critical security vulnerability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants