Can local storage ever be considered secure? [closed]
Asked Answered
C

6

195

I'm required to develop a web application that will function offline for long periods. In order for this to be viable I cannot avoid saving sensitive data (personal data but not the kind of data you would only store hashed) in local storage.

I accept that this is not recommended practice, but given little choice I'm doing the following to secure the data:

  • encyrypting everything going into local storage using the stanford javascript crypto library and AES-256
  • the user password is the encryption key and is not stored on the device
  • serving all content (when online) from a single trusted server over ssl
  • validating all data going to and from local storage on the server using owasp antisamy project
  • in the network section of the appcache, not using *, and instead listing only the URIs required for connection with the trusted server
  • in general trying to apply the guidelines suggested in the OWASP XSS cheat sheet

I appreciate that the devil is often in the detail, and know there is a lot of scepticism about local storage and javascript-based security in general. Can anyone comment on whether there are:

  • fundamental flaws in the above approach?
  • any possible solutions for such flaws?
  • any better way to secure local storage when an html 5 application must function offline for long periods?

Thanks for any help.

Catechin answered 24/6, 2013 at 16:29 Comment(9)
"I accept that this is not recommended practice" - Is it so? Isn't it the opposite that it has been created actually for that?Broadcast
To clarify, I meant not recommended practice to store sensitive data in local storage.Catechin
Like that you shouldn't pass sensitive data over large networks?Broadcast
@Catechin Why does the application have to function have to run for extended periods of time offline? What are the users like? What browsers do you have to support? I for one think it's possible but I need to know specifics about your scenario.Liggins
@Catechin Seeing the updated question, if you are able to restrict users to running the browser in no-addon mode I think this is viable.Liggins
your approach is fine, if you add a pbkdf into the mix and block side-channels with a CSPTerrieterrier
Are you trying to prevent the user from accessing the data, or are you trying to prevent someone who steals the user's computer from accessing the data?Hemorrhoid
How about Nodejs encryption?Citify
There are some good notes at cheatsheetseries.owasp.org/cheatsheets/…Macropterous
H
84

WebCrypto

The concerns with cryptography in client-side (browser) javascript are detailed below. All but one of these concerns does not apply to the WebCrypto API, which is now reasonably well supported.

For an offline app, you must still design and implement a secure keystore.

Aside: If you are using Node.js, you can use WebCrypto/node or the builtin crypto API.

Native-Javascript Cryptography (pre-WebCrypto)

I presume the primary concern is someone with physical access to the computer reading the localStorage for your site, and you want cryptography to help prevent that access.

If someone has physical access you are also open to attacks other and worse than reading. These include (but are not limited to): keyloggers, offline script modification, local script injection, browser cache poisoning, and DNS redirects. Those attacks only work if the user uses the machine after it has been compromised. Nevertheless, physical access in such a scenario means you have bigger problems.

So keep in mind that the limited scenario where local crypto is valuable would be if the machine is stolen.

There are libraries that do implement the desired functionality, e.g. Stanford Javascript Crypto Library. There are inherent weaknesses, though (as referred to in the link from @ircmaxell's answer):

  1. Lack of entropy / random number generation;
  2. Lack of a secure keystore i.e. the private key must be password-protected if stored locally, or stored on the server (which bars offline access);
  3. Lack of secure-erase;
  4. Lack of timing characteristics.

Each of these weaknesses corresponds with a category of cryptographic compromise. In other words, while you may have "crypto" by name, it will be well below the rigour one aspires to in practice.

All that being said, the actuarial assessment is not as trivial as "Javascript crypto is weak, do not use it". This is not an endorsement, strictly a caveat and it requires you to completely understand the exposure of the above weaknesses, the frequency and cost of the vectors you face, and your capacity for mitigation or insurance in the event of failure: Javascript crypto, in spite of its weaknesses, may reduce your exposure but only against thieves with limited technical capacity. However, you should presume Javascript crypto has no value against a determined and capable attacker who is targeting that information. Some would consider it misleading to call the data "encrypted" when so many weaknesses are known to be inherent to the implementation. In other words, you can marginally decrease your technical exposure but you increase your financial exposure from disclosure. Each situation is different, of course - and the analysis of reducing the technical exposure to financial exposure is non-trivial. Here is an illustrative analogy: Some banks require weak passwords, in spite of the inherent risk, because their exposure to losses from weak passwords is less than the end-user costs of supporting strong passwords.

🔥 If you read the last paragraph and thought "Some guy on the Internet named Brian says I can use Javascript crypto", do not use Javascript crypto.

For the use case described in the question it would seem to make more sense for users to encrypt their local partition or home directory and use a strong password. That type of security is generally well tested, widely trusted, and commonly available.

Hagiarchy answered 10/7, 2014 at 13:17 Comment(1)
There's additional documentation (citations) available for the general stance of "do not use JavaScript crypto" provided by the NCC Group from 2011: JavaScript Cryptography Considered Harmful (notably due to the catch-22 of downloading the tool to verify the downloads… PRNG quality… etc.)Parasitic
P
63

Well, the basic premise here is: no, it is not secure yet.

Basically, you can't run crypto in JavaScript: JavaScript Crypto Considered Harmful.

The problem is that you can't reliably get the crypto code into the browser, and even if you could, JS isn't designed to let you run it securely. So until browsers have a cryptographic container (which Encrypted Media Extensions provide, but are being rallied against for their DRM purposes), it will not be possible to do securely.

As far as a "Better way", there isn't one right now. Your only alternative is to store the data in plain text, and hope for the best. Or don't store the information at all. Either way.

Either that, or if you need that sort of security, and you need local storage, create a custom application...

Pegmatite answered 24/6, 2013 at 16:34 Comment(15)
Thanks for your response ircmaxell. The article you link to is one of the first things I read when considering this and obviously raises a lot of red flags. That said many of the points made don't apply to this specific use case. Because I am interacting with only one trusted server over SSL then I would have thought this does allow for a reliable mechanism to get the crypto code into the browser? As for js design not facilitating it to be run securely, are you referring to matasano's reference to content-controlled code?Catechin
@user1173706: partially. What I mean is that being such a dynamic language means that even defining the algorithms doesn't mean that another malicious code can't get at it. For example: Imagine a user installs a plugin into the browser. Now all of a sudden, your crypto code is vulnerable because that plugin has access to do whatever they want (including stealing keys). Check this out.Pegmatite
Downvoter: can you provide a better answer? I realize that this is a somewhat controversial issue where there's significant disagreement between security professionals (and non-professionals as well), so the alternate view-point would be worth sharing. Unless you're downvoting for another reason, in which case how can I improve this answer?Pegmatite
Haters gonna hate. Thank you for all your answers and congrats on 1000 answers milestone!Passel
@Pegmatite not me, but I disagree with this answer. "The problem is that you can't reliably get the crypto code into the browser, and even if you could, JS isn't designed to let you run it securely." - Why? What's the inherent problem? You can use the Stanford JavaScript encryption library and encrypt/decrypt in it. You can hash, and you can do everything securely. I don't see the inherent problem here in an offline app in JS doing standard crpyto, much like an app built in any other language would.Liggins
@BenjaminGruenbaum: the problem is that there's multiple places where that crypto-code would need to interact with third party code. The whole point of that article I linked to is that you can't control the execution environment. So you install the Stanford Crypto lib. Then what happens if some browser plugin overrides sjcl.encrypt to email the key to the attacker? In JS that's 100% possible and there's nothing you can do to stop it. And that's the underlying point. There are no "security" mechanisms in place to prevent other JS from doing nasty things to your data. And that's a problem.Pegmatite
@Pegmatite If you sleep with dogs you can't expect not to wake up with fleas. If the user installs a malware add on that's just the same as the user installing a virus on their PC, it's no different from it. Your Java or C program can be as secure as it gets but as soon as the attacker has the ability to run code you're screwed. That's not different for JS. Addons don't just magically appear in the browser. Moreover, not saving the information encrypted would not help in any way if the user has malware, since it could just hijack the data live.Liggins
@BenjaminGruenbaum: disagree. In a normal application, you'd need either to compromise the app itself (to read memory locations), or gain root access to the box (compromise the OS). Either way, you need to compromise something deeper than just do normal behavior. JS allows this in normal behavior. Which is the problem...Pegmatite
@Pegmatite Disagree. Like a normal application you need either compromise the app itself (read the local storage within) or gain root access to the 'box' (the browser). Either way, you're compromising something deeper than normal behavior. That's exactly the same. It's very hard to install an extension 'by mistake' in practice (you get a big box that you have to confirm when you install, just like UAC in windows or asking for admin permissions in linux). That's still not an inherent problem with web js and certainly something that can be mitigated through careful design.Liggins
See continued debate on the issue between me and @Pegmatite hereLiggins
@Pegmatite upvote from me - thanks for the info. Still not totally clear on this though - please see updated question.Catechin
Now the Encrypted Media Extensions are implemented, I still don't see how they are useful outside of encrypting media (e.g. Video)...Excitant
To partially debunk the "JavaScript Crypto Considered Harmful" article cited above where it depends on the security of SSl/TLS; it's widely known that "SSL inspection" is commonplace and TLS proxies aren't easily detected unless one manually checks the presented certificate's fingerprint. So, the whole idea of "just run the connection over TLS to be safe" is flimsy and illusory.Sidonie
Custom app is also hard. reddit.com/r/sysadmin/comments/xe7cni/…Owlish
The matasano.com/articles/javascript-cryptography seems to be broken.Macropterous
H
16

As an exploration of this topic, I have a presentation titled "Securing TodoMVC Using the Web Cryptography API" (video, code).

It uses the Web Cryptography API to store the todo list encrypted in localStorage by password protecting the application and using a password derived key for encryption. If you forget or lose the password, there is no recovery. (Disclaimer - it was a POC and not intended for production use.)

As the other answers state, this is still susceptible to XSS or malware installed on the client computer. However, any sensitive data would also be in memory when the data is stored on the server and the application is in use. I suggest that offline support may be the compelling use case.

In the end, encrypting localStorage probably only protects the data from attackers that have read only access to the system or its backups. It adds a small amount of defense in depth for OWASP Top 10 item A6-Sensitive Data Exposure, and allows you to answer "Is any of this data stored in clear text long term?" correctly.

Hardigg answered 6/1, 2015 at 17:30 Comment(0)
C
3

This is a really interesting article here. I'm considering implementing JS encryption for offering security when using local storage. It's absolutely clear that this will only offer protection if the device is stolen (and is implemented correctly). It won't offer protection against keyloggers etc. However this is not a JS issue as the keylogger threat is a problem of all applications, regardless of their execution platform (browser, native). As to the article "JavaScript Crypto Considered Harmful" referenced in the first answer, I have one criticism; it states "You could use SSL/TLS to solve this problem, but that's expensive and complicated". I think this is a very ambitious claim (and possibly rather biased). Yes, SSL has a cost, but if you look at the cost of developing native applications for multiple OS, rather than web-based due to this issue alone, the cost of SSL becomes insignificant.

My conclusion - There is a place for client-side encryption code, however as with all applications the developers must recognise it's limitations and implement if suitable for their needs, and ensuring there are ways of mitigating it's risks.

Chromomere answered 7/7, 2015 at 10:57 Comment(1)
Historically there have been extraordinary costs (mechanical, not financial) associated with initial connection negotiation. To the point that corporations would utilize dedicated SSL termination appliances, which could become financially costly beyond certificate issuance and assurance costs. Today many of those issues have been resolved, such as extended duration session persistence to avoid the initial handshake on subsequent requests.Parasitic
N
2

Not accessible to any webpage (true) but is easily accessible and easily editible via dev tools, such as chrome (ctl-shift-J). Therefore, custom crypto required before storing the value.

But, if javascript needs to decrypt (to validate) then the decrypt algorithm is exposed and can be manipulated.

Javascript needs a fully secure container and the ability to properly implement private variables and functions that are available only to the js interpreter. But, this violates user security - since tracking data can be used with impunity.

Consequently, javascript will never be fully secure.

Neisa answered 16/6, 2016 at 21:58 Comment(0)
P
-36

No.

localStorage is accessible by any webpage, and if you have the key, you can change whatever data you want.

That being said, if you can devise a way to safely encrypt the keys, it doesn't matter how you transfer the data, if you can contain the data within a closure, then the data is (somewhat) safe.

Peddada answered 29/3, 2016 at 16:45 Comment(8)
It is not acccessible to "any webpage". It is only accessible to pages in the current domain.Ozonosphere
@dtabuenc to the contrary, I made a pen a while back that shows you every single key/value pair in your localStorage, without any hacks.Peddada
Nope! Sorry. Local storage is isolated per-domain. Code running in one domain can not access values that were stored into local storage by another domain. For example, google.com stores a bunch of stuff in local storage. You will not be able to list any of the keys from google.com in your pen example.Ozonosphere
@dtabuenc tested it, you're right.Peddada
@DanielTabuenca can you provide some source that further explains your answer?Rebellious
Just google any article about local storage, local storage is bound and protected by the same origin policy.Ozonosphere
It would seem there are ways to get data from local storage by exploiting the bookmarks and getting a user to run the bookmark while the site is open. twitter.com/Serpent/status/1485002643370037254Colner
@DaveThompson in this case the user opens his discord before clicking on the bookmark, which means that the user is in the discord domain, so the script can read the localstorage related to discordKhamsin

© 2022 - 2024 — McMap. All rights reserved.