Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Secure cryptographic key storage in the browser and Node.js

License

NotificationsYou must be signed in to change notification settings

47ng/session-keystore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

session-keystore

NPMMIT LicenseContinuous IntegrationCoverage StatusDependabot Status

Secure cryptographic key storage in the browser and Node.js

Ideal to store keys derived from user credentials (username/password) inE2EE applications.

Features

  • In-memory storage: no clear-text persistance to disk
  • Session-bound: cleared when closing tab/window (browser-only)
  • Survives hard-reloads of the page (browser-only)
  • Optional expiration dates
  • Event emitter API for key CRUD operations

Installation

$ yarn add session-keystore# or$ npm i session-keystore

Usage

importSessionKeystorefrom'session-keystore'// Create a storeconststore=newSessionKeystore()// You can create multiple stores, but give them a unique name:// (default name is 'default')constotherStore=newSessionKeystore({name:'other'})// Save a session-bound keystore.set('foo','supersecret')// Set an expiration date (Date or timestamp in ms)store.set('bar','supersecret',Date.now()+1000*60*5)// 5 minutes// Retrieve the keyconstkey=store.get('bar')// key will be null if it has expired// Revoke a single keystore.delete('foo')// Clear all keys in storagestore.clear()

CRUD Event Emitter

Event types:

  • created
  • read
  • updated
  • deleted
  • expired

Listen to events on a keystore with theon method:

importSessionKeystorefrom'session-keystore'conststore=newSessionKeystore()store.on('created',({ name})=>console.log('Key created: ',name))store.on('updated',({ name})=>console.log('Key updated: ',name))store.on('deleted',({ name})=>console.log('Key deleted: ',name))store.on('expired',({ name})=>console.log('Key expired: ',name))store.on('read',({ name})=>console.log('Key accessed: ',name))

Note:deleted will be called when the key has been manually deleted,andexpired when its expiration date has arrived.

When setting a key that is already expired,created orupdated willNOT be called, andexpired will be called instead.

TypeScript

session-keystore is written in TypeScript. You can tell a store about the keys it is supposed to hold:

importSessionKeystorefrom'session-keystore'conststore=newSessionKeystore<'foo'|'bar'>()store.get('foo')// okstore.get('bar')// okstore.get('egg')// Error: Argument of type '"egg"' is not assignable to parameter of type '"foo" | "bar"'

This can be handy if you have multiple stores, to avoid accidental key leakage.

How it works

Heavily inspired from theSecure Session Storage implementation byProtonMail,itself inspired from Thomas Frank'sSessionVars.

Read thewriteup article onmy blog.

From the ProtonMail documentation:

However, we aim to deliberately be non-persistent. This is useful fordata that wants to be preserved across refreshes, but is too sensitiveto be safely written to disk. Unfortunately, although sessionStorage isdeleted when a session ends, major browsers automatically write itto disk to enable a session recovery feature, so using sessionStoragealone is inappropriate.

To achieve this, we do two tricks. The first trick is to delay writingany possibly persistent data until the user is actually leaving thepage (onunload). This already prevents any persistence in the face ofcrashes, and severely limits the lifetime of any data in possiblypersistent form on refresh.

The second, more important trick is to split sensitive data betweenwindow.name and sessionStorage.window.name is a property that, likesessionStorage, is preserved across refresh and navigation within thesame tab - however, it seems to never be stored persistently. Thisprovides exactly the lifetime we want. Unfortunately,window.name isreadable and transferable between domains, so any sensitive data storedin it would leak to random other websites.

To avoid this leakage, we split sensitive data into two shares whichxor to the sensitive information but which individually are completelyrandom and give away nothing. One share is stored inwindow.name, whilethe other share is stored in sessionStorage. This construction providessecurity that is the best of both worlds - random websites can't readthe data since they can't access sessionStorage, while disk inspectionscan't read the data since they can't accesswindow.name. The lifetimeof the data is therefore the smaller lifetime, that ofwindow.name.

License

MIT - Made with ❤️ byFrançois Best

Using this package at work ?Sponsor me to help with support and maintenance.


[8]ページ先頭

©2009-2025 Movatter.jp