What are the valid use cases for client side encryption? - javascript

I just read about the Stanford Javascript Crypto Library (jsfiddle example) which supports SHA256, AES, and other standard encryption schemes entirely in javascript. The library seems very nifty, but I don't know of a reasonable use case for it.
As some questions have already pointed out, client side encryption is not a safe way to pass secure data to a server. HTTPS should be used instead. So, are there any projects that would benefit from or require client side encryption?

Use Case 1
How about local storage? You might want to store some data, but encrypt it so that other users of the computer cannot access it?
For example:
User connects to server over HTTPS.
Server authenticates user.
Server serves an encryption password specific to this user.
User does some stuff locally.
Some data is stored locally (encrypted with the password).
User wanders off
User comes back to site at later stage.
User connects over HTTPS.
Server authenticates user.
Server serves the user's encryption password.
Client-side JS uses encryption password to decrypt local data.
User does something or other locally with their now-decrypted, in-memory local data.
This could be useful in cases where you have a fat client, with lots of (sensitive) data that needs to be used across sessions, where serving the data from the server is infeasible due to size. I can't think of that many instances where this would apply...
It could also be useful in cases where the user of the application generates sensitive data and that data does not need to (or shouldn't) ever be sent to (or stored on) the server.
For an applied example, you could store the user's credit card details locally, encrypted and use JS to auto-enter it into a form. You could have done this by instead storing the data server side, and serving a pre-populated form that way, but with this approach you don't have to store their credit card details on the server (which in some countries, there are strict laws about). Obviously, it's debatable as to whether storing credit card details encrypted on the user's machine is more or less of a security risk than storing it server side.
There's quite probably a better applied example...
I don't know of any existing project which use this technique.
Use Case 2
How about for performance improvements over HTTPS, facilitated via password sharing?
For example:
User connects to server over HTTPS.
Server authenticates user.
Server serves an encryption password specific to this user.
Server then redirects to HTTP (which has much less of an overhead than HTTPS, and so will be much better in terms of performance).
Because both the server and the client have the encryption password (and that password was shared over a secure connection), they can now both send and receive securely encrypted sensitive data, without the overhead of encrypting / decrypting entire requests with HTTPS. This means that the server could serve a web page where only the sensitive parts of it are encrypted. The client could then decrypt the encrypted parts.
This use case is probably not all that worthwhile, because HTTPS generally has acceptable performance levels, but would help if you need to squeeze out a bit more speed.
Use Case 3
Host proof storage. You can encrypt data client side and then send it to the server. The server can store the data and share it, but without knowing the client's private key, it cannot decrypt it. This is thought to be the basis for services such as lastpass.

Like anything on the client, you can use obfuscation to make things more difficult for casual users to peek inside, but since the client would also need to have a copy of the decryptor there's nothing to stop the user from using the decryptor themselves either.
JavaScript is an insecure environment, period.

One use that comes to mind is host-proofing. That is where you want to store the data on the server or store and forward through the server but not give the server access to the data.
The client can encrypt the data prior to transmission to the server and keep the private key or at least the password for the private key locally.
I believe that this is the basis for services such as lastpass.

Related

Client Server Encryption

I have Xamarin as my mobile client, node.js as my backend and MongoDB as database. I am trying to encrypt the user's data and save it in Database. If I do server encryption, still hackers can see the data while transmitting through APIs. Should I do client encryption, pass the data to API and store it in Database or should I do double layer encryption (i.e) Encrypting user data from client side, pass it through API, again do a server-side encryption and store it in Database. Basically, I wants to know how client server encryption works in real world.
The concern is that user's data is sensitive and needs protection even if the database is hacked.
There are several points where we can apply encryption, this is a bit confusing, but let me explain this to you part-by-part.
Database encryption
Your concern about the safety of sensitive data even if the server is hacked is justified. So, whatever sensitive information you have, you will need to encrypt. However, there are several ways to achieve encryption. To avoid overcomplication, I will speak about two types of encryption for this level:
one-way encryption
two-way encryption
The user's password is a data that is only interesting for the user in its raw form. So, you can apply one-way encryption, that is, given the password of the user you know how to encode it, so you store the encrypted version of the password and subsequently whenever the user logs in, validate his/her password by comparing the result of encrypting whatever he/she typed in vs. what is stored in the database. However, you should not be able to decrypt the encrypted password, because passwords need a single direction anyway, that looks like:
user types the value
which is sent to the server
which receives it
and encrypts the raw password
and then compares the encrypted version of the received password with the encrypted password that is stored
The other way to encrypt data at this level is a two-way encryption, that is, an encryption method that you can actually decrypt. You need to use this approach for any data that you may need in raw form for some reason, like showing it to the user.
Server encryption of data sent to the user
If your project owner is worried about the safety of your user's device/application (like the vulnerability of browsers using unsafe extensions or users visiting strange sites with their browser), then some data sent to the user can be encrypted. Avoid this unless you are specifically needing to perform such an act.
Client encryption of data sent to the server
If the communication channel is unsafe, then you might need to apply some encryption on client-side before sending the values to the server.
Good news! HTTPS!
HTTP stands for HyperText Transmit Protocol. Its HTTPS version is already encoding the messages, it stands for HyperText Transmit Protocol Secure. If you are already using HTTPS as a protocol, then your client-side requests are already encrypted, so a third-party listening to the requests you are sending will receive some gibberish of data at request send and response receive events.
Summary
If you are not asked for further encryptions, then you should use HTTPS and one-way-encoding of passwords on your database, because this is the real-world approach in general. If you need to perform further safety-measures either because you have further sensitive user information or some genuine worry about some aspect of the project, or just a requirement, then you can extend this approach with whatever else you need. But HTTPS and one-way encoding the password on database level is an absolute must.

Efficient way to do payload signing in HTML5 SPA

I'm looking to implement some efficient (i.e. with good performance) logic that does payload signing in our web application. The goal is for the HTML5 client to have a guarantee that the contents of a received payload are indeed those that were generated by our backend.
We don't want to do payload hash generation with shared salt because the user can easily open the HTML5 source and find the salt phrase.
We have implemented RSA signing for now where our backend adds a payload signature using its Private Key and our HTML5 client validates it using its baked in Public Key. However the signature generation process takes 250ms (for a relatively small payload) and due to the nature of the signed request this amount of time is unacceptable.
The only other idea is to generate a shared secret at runtime every time a client initializes its session with the backend. The secret however can't be sent in plaintext form so it seems we're going to have to implement a Diffie-Hellman exchange mechanism, something we'd like to avoid if possible or automate with existing libraries.
Remember that the secrecy and encryption need to be done at the Application layer, due to the nature of how we sell our product. We're not looking to encrypt our traffic, this is something that our customers might or might not implement (since it's an intranet application). However, we have to avoid exposing stuff that are related to our licensing checking mechanisms etc to them. The backend is not cloud based and is not controlled by us, but installed on the customers' machines, on premises.
Frontend is Javascript and backend is Java.
Note that Diffie-Hellman exchange mechanism is not protected against MITM attack, therefore not encrypting traffic means that you need to authenticate the DH data coming from the server. This is why a web server using a DH-based cipher suite signs the DH elements sent over the network with the private key of its server certificate, for the client to check that those elements are really from the server that he wants to connect to. Those elements are public but need to be signed.
What you call "payload hash generation with shared salt" is a keyed-hash message authentication code, so it is based on a shared secret, as you noticed, and since you do not want to use this mechanism, it means that you do not trust the client. Therefore, you have to use asymetric cryptography to sign your payload.
Signing a server payload with an asymetric algorithm means that you first need to let the server share a public key with the client. Since you do not encrypt data between the client and the server, you need to deploy the server public key inside the client source code.
You talk about the signature generation process, but the signature check process on the client side is also very important in your case, because the total time the user has to wait for the result is the addition of the time to sign and the time to check the signature (moreover, the signature can often be anticipated on the server, if the data to sign is not dynamically generated, but the verification can never be anticipated). So you need a rapid way of checking a signature on the client side. First, sign a hash, not the whole payload. Then choose the fastest asymetric signature algorithm that is available in your development environment, on the client side. Note that checking an RSA signature is faster that checking a DSA or ECDSA one, for respective keys length corresponding to the same security level. So you should stay with RSA.
All of this until this line may not help you so much! Now there is a way to increase the performances using RSA to sign and verify signatures, and this way is rather the same that SSL/TLS implements to increase browser performances when downloading multiple pages or other objects from the same server: use a session cache. You share a common secret for a specific session with one specific user. Never use this common secret for other sessions. When the user is connecting for the first time, use RSA only once, to exchange an ephemeral shared secret or exchange DH material to create this shared secret. Then, each time the server needs to sign an object, it creates a keyed-hash message authentication code with this specific secret. Therefore, if the user finds the secret, for instance using the debug mode of his browser, it's not a problem: this secret is only here to help him know that something that comes from the server has not been altered. So the user can not use this secret to alter data exchanges between the server and other users.
We ended up by using TweetNaCl both on the client and on the server side. The library provides a every easy and fast way to do DH-like shared secret exchange without going through a custom implementation. With an ephemeral shared secret we can easily generate hashes instead of signatures for our payloads dropping from 250ms to 10μs. Also RSA signing the initial DH exchange is important and the only place we use RSA.
Please read #AlexandreFenyo answer for proper theory on how to usually handle such cases.

What are the scenarios which using Cryptography in JavaScript could make sense?

My friend has an idea about protecting the stored cookies in browser with adding an encryption on them using library such as Stanford Javascript Crypto Library.
Meanwhile i believe such actions are not possible because, javascript has no access to file system.
The question is:
what would be the functionality the said library?
What does it encrypt? I believe the encryption of it would be limited to variables of js application and not files on the host
You're asking
What kind of data could be encrypted using javascript?
and Bergi answered that in the comments:
In general, you can encrypt all data that can be represented in binary
That's true, but this is not what you're actually trying to ask. I believe you're looking for scenarios where crypto libraries are useful in the browser. But more on that a little further down.
I believe the encryption of it would be limited to variables of js application and not files on the host
Yes and no. Anything that can be accessed by JavaScript, can be encrypted. Whether this encryption adds any security is a whole other issue. Values that are accessible through variables in JavaScript code can be encrypted. The same goes to user input which includes files that the user explicitly opened in order to upload in a file dialog (example).
Additionally, your JavaScript code has access to the whole file system in Chrome if you really want it.
Here are some scenarios where using Cryptography in JavaScript could make sense, but not all of them are recommended (not exhaustive, but common):
File storage (i.e. Mega) where the symmetric encryption key is never sent to the server but kept on the client or is directly entered by the user. Its security depends on your trust that the service provider doesn't change their own JavaScript and log the key that was used for encryption.
Password-manager (i.e. clipperz) is similar to file storage, but its code is injected to other sites and it must be resilient to not blurt out all its secrets. It can use many different cryptographic primitives.
Poor-man's HTTPS (i.e. too many Stack Overflow questions) where the server has its RSA private key and sends the RSA public key over HTTP (sic!) to the browser. The browser can encrypt any data and send it back to the server (maybe also establishing a symmetric key in the process). The server can decrypt the message with its private key and respond. This is sort-of secure as long as there is no man-in-the-middle attacker that simply injects its own JavaScript that copies any browser data to the attacker's server. SJCL implements ElGamal encryption instead of RSA for this use case.
Hashing data before uploading in order to check for transmission errors or achieve deduplication (no need to upload file, because somebody else already did so). Hashing is technically in the realm of cryptography and many libraries to that.
Online calculators (i.e. my authenticated encryption tests) where valid and easy to use implementations or algorithms can be used directly when implementing the same algorithms in another language. The data is never sent to the server and is encrypted purely in the browser. My "calculator" can be used to test ones own implementation, because it is verified by various test vectors. Others are there to help friends pass hidden messages without proper e-mail encryption.
These should not be done with browser-based crypto:
If you're using only symmetric encryption over HTTP and the exact same key is present at the server and the client, then you have a problem, because the key must be sent in some way for the client to the server or back. If you send the encryption key from the server to the client or the other way around you need to encrypt your symmetric encryption key. The easiest way to do this would be to use TLS. If you use TLS, then the data as well as key are encrypted, so you don't need to encrypt it yourself. This doesn't provide any security, just a little bit of obfuscation. Any passive attacker (observer) can read your messages. You should read: Javascript Cryptography Considered Harmful
Hashing a password for log in is a bad practice. The general consensus is that you need to hash a password many times (PBKDF2, bcrypt, scrypt, Argon2) in order to check whether a user has sent the correct username and password. Some think that if we hash on the client, the password is not sent in the clear over the network and everything is secure. The problem is that if they think that, they are not using HTTPS (which they need). At the same time, the hashed password is their new password. If the server doesn't implement a constant-time comparison, it is trivial to use a timing side-channel attack to log in as any person which you know the username of.
JWT for sessions: Part 1 and part 2
Cookies are in fact accessible via JavaScript, just like the DOM is.
You could encrypt them by running the value you want to store through the encryption algorithm.
Depending on what you want to store and how the encryption/decryption mechanism works this may or may not be a good idea.

Javascript asymmetric encryption and authentication

Some of the guys here are developing an application which incorporates some 'secure areas' accessible by logging in. In the past, the login form and subsequent 'secure' pages were all plain text transmitted over http, as it's an application that goes out for use on shared servers where there is little chance of being able to use SSL (think WordPress and the like). Most people just shrugged their shoulders as that's all they expected - it's hardly a national bank.
We are now thinking of writing the next version using a JavaScript front end, with the advantage of loading all the images & CSS once, then writing HTML into the DOM thereafter with extJS (or maybe jQuery). We'd like to encrypt user input at the client before being sent to the server, then decrypt server output at the browser before being rendered to HTML so as to introduce some sort of security for users. There are also gains to be had with reducing page loading times, as we're only sending gzipped JSON back and forth.
While playing around, we realised that the method we were looking at to encrypt the basic stuff also doubled up as an authentication mechanism for login in the first place.
For simplicity...:
The user connects to the login page over standard http, where the browser downloads the JavaScript package containing the hashing and encryption algorithms (SHA-256 and AES for example).
User enters username, password and secret into a login form.
The browser JavaScript sends a hash of username and password to the server via AJAX. The secret is only stored in JavaScript and is never sent across the internet.
The server looks up the hash and retrieves username and secret from the database.
The server sends a hash (same algorithm as the browser) of username and secret back to the browser.
The browser JavaScript creates a hash of username and secret and compares it to the hash sent back from the server.
If they are the same, the browser JavaScript encrypts response with secret and sends the message back to the server.
The server decrypts the message with secret to find the expected response and starts a new session.
Subsequent communications are encrypted and decrypted both ways with secret.
There seem to be a few advantages of this type of system, but are we right in thinking:
The user knows they are talking to their server if the server manages to create a hash of username and secret, proving the server knows and understands username and secret.
The server knows the user is genuine if they manage to encrypt response with secret, proving the user knows secret.
At no time is secret ever transmitted in plain text, or is it possible to determine secret from the hash.
A sniffer will only ever find out the 'secure' URL and detect compressed hashes and encryptions in the query string. If they send a request to to the URL that is malformed, no response is given. If they somehow manage to guess an appropriate request, they still have to be able to decrypt it.
It all seems quick enough as to be imperceptible to the user. Can anyone see through this, as we all just assumed we shouldn't be playing with JavaScript encryption!
Don't do this. Please use SSL/TLS. See Javascript Cryptography Considered Harmful.
If you can provide a single SSL site to deliver your JavaScript securely (to avoid the attack mentioned above), then you can use the opensource Forge library to provide cross-domain TLS connections to your other sites after generating self-signed certificates for them. The Forge library also provides other basic crypto stuff if you opt to go in a different direction. Forge has an XMLHttpRequest wrapper that is nearly all JavaScript, with a small piece that leverages Flash's socket API to enable cross-domain communication.
http://digitalbazaar.com/2010/07/20/javascript-tls-1/
https://github.com/digitalbazaar/forge

How to encrypt a value on the client and pass it through a web server without decrypting it

Hey everyone, I am researching a project where we would need to keep a value encrypted from the client all the way to a black box system without decrypting it at any point in between. We are using SSL between the browser and web server, but the values are automatically decrypted at the web server, which is what we need to keep from happening. We need to be able to pass it through the web server (still encrypted) and through other back end systems until it hits its final destination where it would be decrypted.
So my question is what options are available to us for maintaining an encrypted state for a value from the browser back, without decrypting it anywhere along the way?
Thanks
Mark
Have you thought about doing a simple RSA encryption on the values and sending that through the system? You will need to make sure the clients have the public key in which to encrypt the data with, but that would be easy and secure enough to pass around.
To my knowlege, most libraries out there will support RSA. A nice demo of how to do it purely in Javascript can be found here.
you'll want to take a look at public key encryption. SSL protects your session (browser <-> server) but not the full transport. i'd suggest encrypting your data once it's received from the client, then sending the encrypted data all the way in.
here's a terrible diagram outlining the flow of data
client browser web server random server blackbox
route ---- SSL -------------><------------- not encrypted ------->
data *-------- PGP/GPG encrypted --------->
basically your data is encrypted via SSL to the web server, where it is PGP/GPG encrypted, then sent downstream. SSL doesn't matter at this point (or at least, isn't the primary form of encryption).
unless you can guarantee javascript in your environment, it may be better to encrypt at the web server to make sure your data is secure if the user has javascript off for some reason.
If you use a binary type in your database, the web server should send it as-is. Your client can then encrypt the data before inserting it, and would then have to decrypt the data after fetching it. Neither the web server nor the database server itself would be able to view the data.
The black box system, by definition, can't decrypt the data unless it was built to do that. I'll suggest discussing the problem with the developers of the black box system.

Categories

Resources