0

I'm currently building a web application that utilises Open Banking through Plaid. This means that it pulls a users banking details through a generated 'access token'.

I've been toying with the concept of how to persist this user data. My reasoning for this is that the Plaid API gets pulled on every web page that requires it, and so it causes a several second 'loading' to process - which if you're navigating round my app is frustrating.

This is a poor user experience in my opinion, and so I'd prefer to somehow persist this data without having to make a server call.

To do this, I've initially gone for session storage. I know many people say this is vulnerable to things such as XSS etc, but it's convenient and works well.

I'm a little uneasy with storing the results of a server call locally though, for obvious reasons.

Currently, the data which is pulled and therefore stored locally is:

  • Firebase user ID
  • Account id
  • Balance
  • Type of account
  • Last four digits of account number
  • Account provider
  • Consent expiration time
  • Transactions
  • Database ID

And a bunch of other status codes.

The actual data itself isn't personally identifiable, or usable for anything malicious to my knowledge. No passwords are stored locally, the access token is only ever exchanged via my server, and it is encrypted so not publicly visible as plain text should my database ever get hacked.

So I guess my question is, how secure is this? Is it actually a security problem considering the data can't be explicitly used for malicious purposes? The only time it would be a problem (in my opinion) would be if my server / database was accessed with the encryption key.

Other alternatives are..

  • Encrypt the data that is stored in session storage, but is this pointless?
  • Not use session storage at all

Or can anybody suggest any other alternatives?

I know people on here will be much more experienced than me with this - so open to any suggestions. Please let me know, it'd be appreciated.

2
  • please clarify 'session storage' - is this client-side local storage in the browser, within a cookie, or server-side storage such as eg. PHP $_SESSION[] - i'd be inclined to encrypt the data anyway, because you don't know how it may be exploited in some future case that is not apparent now - you could always use an ephemeral key, generated at time of user login and derived from their details, that is discarded when the user logs/ times out - if you use an authenticated symmetric cipher (tag/ hmac) then you will ensure the integrity of the information, ie. not tampered with by a malign user – brynk Jan 22 at 19:56
  • It’s client side session storage in the browser. :) Agree about the encryption, makes sense regardless I think. Will have a look at other options - but PHP is a no go, not prepared to use that. Thanks for the response! – Jon Nicholson Jan 22 at 20:02
1

Summary

You're storing potentially sensitive user data in the browser, client-side, and from time to time referencing the data. I would store the information using an authenticated symmetric cipher, which (depending on how your key management works) gives a strong guarantee of confidentiality as well as integrity. You use data by:

  • sending the ciphertext to a separate (maybe 3rd-party) web service
  • or, sending the ciphertext back to the application server as part of the http protocol exchange
  • or, decrypting the ciphertext and reviewing the data in the client browser to make some sort of decision

In the first two scenarios, you never have the requirement to decrypt on the client-side - you're fundamentally relying on the client to store session data reliably. I'll assume you're not in the first scenario, as you would be making a service call to obtain the Plaid data (basically what you're trying to avoid!). I'll also assume the key-management strategy code can't be interfered with (... which is a loaded assumption if you plan to do decryption on the client side... more on this later).

Discussion

I would propose that you create input key-material for each client also, for example, vested in the cookie. (A cookie could be a good choice because the user may have stricter rules around cookie destruction.) Another choice would be to store the session key material on the http server or in the data store. I wouldn't store it with the encrypted session data. The client provides the encrypted session data from local-storage, as well as any input_key_material it holds, and the server would then derive key material as needed.

You would be using an authenticated symmetric cipher: Authenticated Encryption with Associated Data. Preferably something like X/ChaCha20Poly1305 or AES-GCM will be up to the task, however, you may need to consult any governance or legislative constraint (eg. some standards restrict your choice to AES-GCM and SHA2).

Generally speaking, this cipher follows the definition: AE( key , nonce , plain_text , assoc_data ), where plain_text is the data you want encrypted, and assoc_data is additional clear-text data that won't be encrypted, but must be authenticated.

It is of critical importance that if plain_text or assoc_data changes then so too must the nonce and/ or the key. If the code results in key + nonce re-use for two different plain_text values, the XOR of the two ciphertexts will be the same as the XOR of the two plaintexts. This may lead to data leakage, particularly if the format is known.

A common way to guard against nonce re-use is to use a counter if the nonce is smaller than 16-bytes, or use a random value if it is 16-bytes or greater (TODO ref). This will depend on what cipher you use for AE. In the case of the former, one solution I've used in the past is to produce a client-session-specific prefix of 8-bytes and then grab 4-bytes from the epoch time. The client holds input_key_material including the 4-byte timer value, while the prefix (as well as the key) are computed on the server as needed, and disposed of immediately after use. The choice of the timer is a relatively safe one, because any adversary will capture packet timing anyway. (Once you've considered all this, you might ask separately about a potential solution.)

Decrypting client-side

The fundamental problem here is delivering code and key to the client securely. If you search on this site, there's plenty of discussion weighing up pros and cons. There is a recent WebCrypto API that will limit you to AES-GCM and SHA2. You'll need a 'good way' to get key material to the browser.

Personally (at time of writing), I don't have strong opinions either way. You use the tools available and accept the risk. I would use the built-in browser API over a 3rd-party Javascript implementation (eg. sodium.js), because I work on the assumption that an implementation within the browser, that can't be surreptitiously replaced by other javascript code, would be less-malleable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.