4

This is by no means a replacement for HTTPS, so please do not assume that is why I am asking this question. I am exploring, and I am curious. I am looking for some expert input on this, and I am not entirely sure where I should ask this.

Okay, so say I'm sending really sensitive information (bank information for example). And I want to take a step further to protect it.

With JavaScript, I would encrypt the form data when it was submitted. Then I would decrypt it on the server (back-end).

  • The first option would be to use asymmetric encryption alone. Encrypt the form data on submission, with the public key. And since it is public, it cannot hurt for the client to know it. Then on the server, decrypt the data with the private key. Which is obviously private, and only the server knows it.

  • A lot of asymmetric algorithms are really slow from what I have heard, and can be quite limited in terms of how much you can encrypt(RSA for example). So what about hybrid encryption? Encrypt the form data with symmetric encryption (random key generated every time), then encrypt the symmetric key with with the public asymmetric key. Send the symmetric key along with the data. Decrypt the key with the private key, use the key to decrypt the data.

What do you think? I am a little lost as to which would be better. And how to go about this.

  • You generally don't use asymmetric encryption for anything but negotiation of a symmetric key. Asymmetric is much slower, and has size limitations. All the being said, HTTPS already does exactly this process. What problem are you trying to solve? – Kritner Sep 19 '18 at 23:26
  • 1
    @Kritner Actually HTTPS these days does more such as ephemeral symmetric keys. – zaph Sep 19 '18 at 23:29
  • 1
    @user10103279 It is very hard to get secure encryption right, the best can easily make poor choices such as TLS authenticate-then-encrypt. It is always better to use well vetted methods. Finally: "Schneier's Law": "Anyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break." – zaph Sep 19 '18 at 23:35
  • 1
    @user10103279 "I'll be using something stronger than RSA", what would that be? – zaph Sep 19 '18 at 23:36
  • 1
    @ user10103279 you seem to misunderstand the references information, it is stating that not to use RSA for data but to use hybrid encryption. Not that RSA is not secure. The scheme suggested is similar to TLS on which HTTPS is built. Just just using RSA or EC for key encryption and a symmetric cipher for the data is not sufficiently secure. – zaph Sep 19 '18 at 23:48
8

Best case scenario here is that you are wasting your time. Generally, doing client side encryption on top of HTTPS in a web application is a lot of work, but it provides no extra security.

The purpose of an extra crypto layer would be to protect against a MITM that has somehow managed to crack the TLS encryption. But an attacker that has done that could easily just modify the JS source of your extra crypto, simply turning it off. So this would only be useful against a passive MITM that has cracked TLS, and that really isn't a threat model worth investing a lot of energy protecting against.

Also note that limitations in many browsers (Opera Mini, IE9) ability to generate secure random numbers makes client side encryption tricky. You should never rely on Math.random for anything crypto related.

You should focus your energy where it has maximum impact. Instead of implementing your own crypto, make sure that you are using the good crypto you get for free with HTTPS correctly. If you are worried about MITM-attacks, looking into HSTS and preloading would be time much better spent.

  • One Thing that Client Encryption can do is to ensure that the Server can't know what the client was sending. Like Chat Messages where the Server isn't allowed to see what the Client was sending to Another Client. – Serverfrog Sep 20 '18 at 13:59
  • 5
    @Serverfrog That's only true as long as the server cooperates. A malicious server could easily just serve some JS that tells the browser to send decrypted message data to the server. – Ajedi32 Sep 20 '18 at 14:05
  • @Ajedi32, That's true. It was just to call out that it isn't a "always Bad" idea to create a encryption on the client side. It is just a very specific problem one will try to solve (and that is done in the past is shown with all the Mobile Messenger we have today, but how trustworthy they are is another question to often asked here) – Serverfrog Sep 20 '18 at 14:07
  • 1
    @Anders iirc, most modern browsers (post-2013) support window.crypto.getRandomValues which should allow decent key generation. – Jesse Daniel Mitchell Sep 20 '18 at 16:20
  • 1
    @JesseDanielMitchell Checked caniuse, and i'ts around 90% globally, mostly because of Opera Mini. Far better than I thought, Ill have to admit. – Anders Sep 20 '18 at 17:37
0

Probably Not, but...

Most of the information described in @Anders response was correct, and should be recognized as the correct response.

If we are assuming that you are performing the encryption specifically for the client-server session taking place, there will be no added benefit over just using HTTPS.

However, since you explained that you're not looking for an alternative to HTTPS, I'm going to assume you are exploring one of the following scenarios:

  1. You're creating a multi-tiered server architecture, where you only want servers with elevated permissions to be able to read the sensitive data.

  2. You want to be able to store the data at rest in some database, but only want some of your servers to be able to read it.

  3. You actually just want client-side encryption, where the server can't read it, but can store it.


Caveat Emptor

All three of these scenarios rely on the assumption that you can trust the server code to some extent. (This could work in structured organizations that have heavy code review).


Traditional Methods

Option 1 could be implemented traditionally by enabling CORS and allowing the client to communicate with your "elevated" server. However, this requires you to open your "elevated" server to the internet.

This typically involves tokenization, and is an approach used by many payment processors.

Option 2 could be implemented server-side, by encrypting symmetrically prior to inserting the data into the database.


Non-Traditional Methods (for the sake of education)

Let's say you have a unique mix of options 1 & 2, or you want to explore option 1 without opening the server to the open web.

Yes, you could use a hybrid crypto-system (asymmetric + symmetric) to effectively encrypt data that only specific servers could decrypt. Implementing such a cryptosystem is a challenge, and requires expansive cryptographic knowledge to do correctly.

For option 3, you could encrypt/decrypt symmetrically client-side to protect the user data. This would likely require a variable to be stored in localStorage (for convenience), which carries risks (it's easier to hide code that scrapes it).

These approaches could assist in making it more difficult for employees in a structured organization to steal user data. But it only works if the data encryption mechanism can't be tampered with, or the credentials can't be stolen.

Encryption won't be a silver bullet in any scenario I can imagine. It can mitigate quite a few attack vectors, but it won't resolve all of them. You'd need intense code review.

  • I didn't want to include this in my official answer, but if you are interested in exploring an implementation of a browser-based cryptosystem, I have an implementation. Keep in mind that I'm an amateur cryptographer; I have zero academic credentials in the field of security. I've delivered lectures to graduate classes, but I'm by no means a professional. – Jesse Daniel Mitchell Sep 20 '18 at 19:13
-4

The system you describe is end-to-end encryption (E2EE), which when deployed correctly can ensure not even the server can access the contents. However, for your usage, the only systems to be able to decrypt the "sensitive information (SI)" will be the client and the server.

Upon submitting the SI you will download the server's RSA public key, likely RSA-2048 will suffice here, as you can generate new key-pairs manually on a frequent basis. RSA with JavaScript could be a good starting point, as it shows how you could encrypt a string with the public key and offers decryption options as well within the source code. Storing the RSA private key secure may prove challenging. You could handle this by using PHP or Python (via a CGI gateway). Then ensure only the compiler has permissions to access private key, this will mitigate risk. As if the web server has access permissions and is ever compromised it could access the private key.

Next, a symmetric encryption key (SEK) is required. I was looking at Generate random string/characters in JavaScript, which while not perfect for this scenario, should give a good building block for what is required.

Having not used an AES JavaScript implementation before I will provide Javascript AES encryption. I felt, 'JSAES is a powerful implementation of AES in JavaScript' seemed like a simple option. However, this will need to be your decision.

Now when you submit the ciphertext (plaintext encrypted AES) to the server, you should ensure the client knows decryption was possible and allow for validation. AES_Encrypt(plaintext, key) so AES_Encrypt("Validated", "$key"). This ensures the server was able to encrypt a message with the (encrypted symmetric key) and the client was able to decrypt the expected message. I should mention AES 128-bit or 256-bit will suffice equally. Obviously, AES 256-bit is better, but given the RSA-2048 is the weakness in the chain, AES 128-bit with RSA-2048 might be more ideal, as overhead will be reduced.

You are now validated. Ensure that the symmetric encryption key is only valid for X minutes, say 60 minutes. Before a new session key is required. This will prevent key-reuse abuse.

To summarise:

  • Fetch RSA public key
  • Generate random 32 character string (symmetric key)
  • Encrypt (symmetric key) with the RSA public key
    • Producing ciphertext
  • Submit the ciphertext to the server for decryption and validation
  • Decrypt the ciphertext with the private key
  • Encrypt the expected (known) message using AES and the symmetric key
    • AES_Encrypt("Validated", "$key")
  • Client decrypts and validates secure authentication is complete.
  • 7
    Never, never use Math.random to generate crypto keys. This is not secure. – Anders Sep 20 '18 at 13:43
  • The correct answer is: Use TLS, it does all of this for you. Also, I'm not clear on what your makeid() is being used for, but I really hope that's not your AES private key. Please use a SecureRandom to generate random bytes. – Mike Ounsworth Sep 20 '18 at 14:00
  • 3
    @safesploit Focus or not, you are suggesting an implementation and I worry that future googlers will take your code and use it for something real. Do you want to edit that out then? – Mike Ounsworth Sep 20 '18 at 14:32
  • 2
    @safesploit There is no good way to produce secure random numbers with JS that works with all browsers. Thats one of the reasons one should not do client side crypto. – Anders Sep 20 '18 at 15:17
  • 3
    The correct answer here is "Use TLS and let the browser do the crypto for you". There is no source code to provide. – Mike Ounsworth Sep 20 '18 at 15:18

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.