Can client-side .js decryption enhance security? - javascript

By a parent-company-wide mandate, I need to structure my web-app that any personally identifiable client information will only be shown to users if the user clicks on a "View" button in the field.
(This isn't a high-level security thing, and it doesn't need ultra-high level encryption. All authenticated and authorized of the app will be able to view the data. The mandate is for the data to be stored encrypted and not decrypted until just prior to display to the end-user. The intent is to eliminate any employee from having easy access to a screen full of sensitive info that could make large-scale information stealing easy for even tech un-savvy. "Locks keep honest people honest.")
The obvious challenge of doing this in javascript is that both the ciphertext and the key would need to be used to decrypt the value, and they'd both have to come from the server(s) via HTTPS. Implemented poorly, the web-app could make the encrypted date easier to get in clear-text since it could expose the keys and shared secrets used by the encryption algorithm.
At minimum, I can send a guid to the client as a limited time one-use-only token to allow them to access an HTTPS web service that would return one item of clear-text data per click of a view button. (Which technically does nothing to enhance security except throttling the speed that the data could be stolen.)
Are there known methods for web apps to use splitting data between an initial request, and a later AJAX request to enhance the data security? I certainly could roll my own system for the AJAX view requests that could use things like time of day, session key, etc. to validate requests, but I'm not sure if that would really get me any benefit -- I would still end up with two options: Responding to the AJAX request via HTTPS with the clear text, or sending both the cipher text and the decryption keys/secrets to a browser to decrypt with.
NOTE: Keep in mind, the only point here is to stop non-techie employees from being tempted to do bad things with "easy-stealing" data. I'm totally comfortable if anyone wants to debunk or prove whether any techniques actually benefit security or are just busy-work that are equally vulnerable.

Related

A safe way to send and show passwords to client

I'm building a password manager site using nodejs on the back end. When the user registers and saves a password I encrypt it and then store it in the db, so it's safe. The problem is that I need a safe way to send it from the database and show it to the user when needed. Which is the best way, send it encrypted to the client and decrypt it with a script or decrypt on the back end before sending it? Is https safe enough to protect requests and responses?
Try encrypt and decrypt at device level, so the only risk you take is getting the master password. A good way to do that is with: https://nodejs.org/api/fs.html.
With FS can you write and read data from device level
When making decisions about cryptography, ask two essential questions:
What is your threat model?
Should you be implementing it yourself or use an existing solution (such as BitWarden, an open-source password manager)?
Your seemingly-simple question is tricky, because Web security in general is a complex topic. In an application such as yours, several layers are involved, and you must decide what to do about each of them in your threat model:
Client/browser
Front-end server
Back-end server (can be the same as the front-end server depending on architecture)
Database
Depending on who controls what, the answers will be different. For example, if you're developing a password manager to be deployed on a company's premises, then it likely won't matter whether you encrypt/decrypt on the "back-end" or on the "front-end", as they'll usually end up being the same host, managed by the same IT people. A compromise of the host can result in injecting malicious code, which can then intercept all passwords, keys, etc. right there in the browser, and it's little help that all crypto is done on the client when the client-side code is controlled by the attacker.
In such cases, what will matter more is policy decisions - e.g. if the passwords sometimes safeguard GDPR-subjected personal records, you may need to implement the principle of least privilege and make the journey of the plaintext passwords as short as possible - whether a server-hosted "site" can ever accomplish this becomes an organizational/legal question, rather than a technical one.
Analyze your threat model carefully - what attack scenarios are you defending against? Do different people own the DB layer and the back-end servers, or could a single person dump all DB data and undetectably replace the client-side JS? What do your defenses protect - data at rest, data in transit? You might find that, depending on your desired security properties, a Web-based password manager is not feasible. On the other hand, it may be that you're after simple, single-tier deployments, in which case your job is easier as you can do crypto on the back-end.
The least you could do, if you decide to roll your own password manager, is to look at existing software and learn from it. Pick something that has been audited (e.g. Bitwarden!), find the audit document, see what pitfalls the original authors had run into.
HTTPS is extremely scrutinized that you can assume it's safe, so long you can keep openssl on your system updated. And honestly, your password manager's implementation or maybe your DB/OS patch level is more likely be vulnerable to attacks.
But to answer your question. In theory, decrypting on client side could be safer, but that is only if the decryption truly happens on client side, and that the decryption key is never transmitted over the wire.
That way, even if somebody else gains access to the data or taps data in transit (even with HTTPS decrypted), they will not be able to decrypt it because they will not get the decryption key.
Afterall, that is basically end-to-end encryption like some messaging app does, just in asynchronous fashion.
And why not ask how others do it if you are doing it. For example, 1Password actually built their own protocol called Secure Remote Password (SRP) and they published a white paper detailing the exact intricacies. So you can definitely take reference.

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.

Sending and receiving encrypted data from a javascript app

I have an interactive html5 app that let's people customize products on the client-side. As a user is customizing, the price updates based on individual component prices.
Once this is done, the person hits checkout, I send the customization to the server, and the server takes over the checkout process.
Obviously sending price data to the server is pointless, since anyone could spoof the POST data. So, I tried writing a server side script that will regenerate the price according to the components selected (sent to the server with the customization data), and show that on checkout instead. However, the server side calculation is proving very difficult, due to complex customizations offered; and it seems like I have to rewrite the entire client-side customization logic on the server-side (which is a lot of work).
Before I continue writing the server-side script I wanted to know if it is at all possible to send the price data to the server in a way (asymmetric key auth perhaps) that cannot be spoofed?
Never trust the information clients send you.
To answer your question, it is possible to use encryption to send data from the client to the server. However, the problem here is the data being encrypted can be modified even before the encryption. So, encryption is not really the solution. The client might modify the data before encryption and the server will not know this if there are no server-side checking.
Even with public-private key encryption, this will still be unsafe. There will only be an assurance that your data will not be tampered from the user to the server. It cannot be spoofed by third parties but your user can spoof it, thereby making the encryption pointless. So, do not trust the user to send you valid legitimate information.
You should really double check everything in the server. And you will not need encryption unless privacy is an issue (which probably is based on your description). This can easily be solved by using https.
The client-side javascript you created can serve as immediate feedback to the users, they see prices as they make changes to the forms. This is good because they do not need to wait for the server to process the information, which the server should upon submission of the form.
You should never never never trust client-side code. If you want to spare yourself the headache of rewriting your client-side code, you could just put the relevant JavaScript on the server and call it from your server code (Not that I'm suggesting you should do that). Another thing I would recommend doing is recalculating the price based on the contents of a full postback once the user is done with their customization, and then displaying the recalculated price to the user in order to allow them to confirm it. That way if any client-side shenanigans have occurred, the user will get the real price anyway, and I'm sure that if it differs even slightly from the previous price, your support people will hear all about it.

Browser-based encryption/decryption with private key from browser keystore

My situation:
Medical staff wants to enter sensitive data of patients into a web browser (!) in order to store it to some database and later retrieve it again.
These data are not allowed to be seen by anyone else except the medical staff itself. This means that it must be encrypted using some secret token before it is transferred to the server. It also means that neither IT staff (having access to the server/database) nor anyone else should be able to decrypt it without the secret token. (If the token is lost, the data would never be accessible anymore.)
No additional software should be installed on the client machine, except some token (e.g., a private key) that one would export once and import it into all browsers from which data access should be granted.
So my question is:
Is there a way to encrypt/decrypt data on the client-side (e.g., using JavaScript) using some secret browser token that can be exchanged between browsers easily (I.e., exported/imported similar to X.509 certificates)?
If not, which alternative solutions would be possible? Since conditions 1 and 2 are mandatory, only condition 3 may be modified, if necessary. However, still as little installation effort as possible should be necessary on the client-side.
EDIT: SSL is obviously only part of the answer to this question!
Take a look at Web-browser encryption of personal health information, whose "Abstract" section seems to describe your same problem. However, their "passcode" that generates the encryption key must be shared, which wouldn't let you differentiate medial staff.
We describe a system for remote data entry that allows the data that
would identify the patient to be encrypted in the web browser of the
person entering the data. These data cannot be decrypted on the server
by the staff at the data center but can be decrypted by the person
entering the data or their delegate. We developed this system to solve
a problem that arose in the context of clinical research, but it is
applicable in a range of situations where sensitive information is
stored and updated in a database and it is necessary to ensure that it
cannot be viewed by any except those intentionally given access.
There's a javascript implementation of AES encryption which encrypts the plaintext in the browser. If you build something around those tools, the server side would store only the encrypted text and would not have the passphrase.
http://www.fourmilab.ch/javascrypt/
Shouldn't require any extra installation on the client side, but probably will require some development effort to get the user experience right.
Due to ProtonMail's efforts, there is now an open source PrivateKey implementation in the browser at: https://openpgpjs.org/
This has had multiple security audits and is the basis of protonmail.com, so it has a fairly good records and maintainer in place. They also have a good summary of important security browser models.
The Web Crypto API has pretty good support in all modern browsers. It supports many algorithms, both symmetric and public key. With a good reminder for the user to keep their keys secure and may be backed up somewhere else, this should be the way to go.

Web services API Keys and Ajax - Securing the Key

This is probably a generic security question, but I thought I'd ask in the realm of what I'm developing.
The scenario is: A web service (WCF Web Api) that uses an API Key to validate and tell me who the user is, and a mix of jQuery and application on the front ends.
On the one hand, the traffic can be https so it cannot be inspected, but if I use the same key per user (say a guid), and I am using it in both then there's the chance it could be taken and someone could impersonate the user.
If I implement something akin to OAuth, then a user and a per-app key is generated, and that could work - but still for the jQuery side I would need the app API key in the javascript.
This would only be a problem if someone was on the actual computer and did a view-source.
What should I do?
md5 or encrypt the key somehow?
Put the key in a session variable, then when using ajax retrieve it?
Get over it, it's not that big a deal/problem.
I'm sure it's probably a common problem - so any pointers would be welcome.
To make this clearer - this is my API I have written that I am querying against, not a google, etc. So I can do per session tokens, etc, I'm just trying to work out the best way to secure the client side tokens/keys that I would use.
I'm being a bit overly cautious here, but just using this to learn.
(I suggest tagging this post "security".)
First, you should be clear about what you're protecting against. Can you trust the client at all? A crafty user could stick a Greasemonkey script on your page and call exactly the code that your UI calls to send requests. Hiding everything in a Javascript closure only means you need a debugger; it doesn't make an attack impossible. Firebug can trace HTTPS requests. Also consider a compromised client: is there a keylogger installed? Is the entire system secretly running virtualized so that an attacker can inspect any part of memory at any time at their leisure? Security when you're as exposed as a webapp is is really tricky.
Nonetheless, here are a few things for you to consider:
Consider not actually using keys but rather HMAC hashes of, e.g., a token you give immediately upon authentication.
DOM storage can be a bit harder to poke at than cookies.
Have a look at Google's implementation of OAuth 2 for an example security model. Basically you use tokens that are only valid for a limited time (and perhaps for a single IP address). That way even if the token is intercepted or cloned, it's only valid for a short length of time. Of course you need to be careful about what you do when the token runs out; could an attacker just do the same thing your code does and get a new valid token?
Don't neglect server-side security: even if your client should have checked before submitting the request, check again on the server if the user actually has permission to do what they're asking. In fact, this advice may obviate most of the above.
It depends on how the API key is used. API keys like that provided by Google are tied to the URL of the site originating the request; if you try and use the key on a site with an alternate URL then the service throws and error thus removing the need to protect the key on the client side.
Some basic API's however are tied to a client and can be used across multiple domains, so in this instance I have previously gone with the practice of wrapping this API in server side code and placing some restrictions on how the client can communicate with the local service and protecting the service.
My overall recommendation however would be to apply restrictions on the Web API around how keys can be used and thus removes the complications and necessity of trying to protect them on the client.
How about using jQuery to call server side code that handles communication with the API. If you are using MVC you can call a controller action that can contain the code and API key to hit your service and return a partial view (or even JSON) to your UX. If you are using web forms you could create an aspx page that will do the API communication in the code behind and then write content to the response stream for your UX to consume. Then your UX code can just contain some $.post() or $.load() calls to your server side code and both your API key and endpoint would be protected.
Generally in cases like this though you proxy requests through the server using 'AJAX' which verifies the browser making requests is authorized to do so. If you want to call the service directly from JavaScript, then you need some kind of token system like JSON Web Tokens (JWT) and you'll have to work out cross-domain issues if the service is located somewhere other than the current domain.
see http://blogs.msdn.com/b/rjacobs/archive/2010/06/14/how-to-do-api-key-verification-for-rest-services-in-net-4.aspx for more information
(How to do API Key Verification for REST Services in .NET 4)

Categories

Resources