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

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.

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.

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.

Can client-side .js decryption enhance security?

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.

Encryption and Decryption in and out of codeigniter

I am creating an application based on codeigniter and will work as a API Centric application, i want to implement security , so that the user accessing the API from their own portal should get a public and private key from my portal and then every request they send to my server to get data should be encrypted by the public key and the server should decrypt the data using the private key getting the private key stored in the database
Now the problem is that how can i implement that, so that the user shouldn't go to hard proceedures to encrypt the data using the public key, and i should also be able to decrypt the information using private key within the codeigniter. and also if the encryption is made by javascript still it should be decrypted via codeigniter. I need some secure method to do that, so that i can avoid man in middle attacks and other threats
Thanks
The easy answer is, use TLS.
If you've implemented your server interface as a web API, then this is as simple as configuring your web server front-end to accept connections over HTTPS. Your web server (and the browser / HTTPS client library on the client side) will then take care of most of the complicated handshaking, authentication and encryption details for you.
TLS is far from a perfect security protocol, but if used properly, it generally does the job, and it does it with much less hassle or opportunities for mistakes than designing your own protocol would.
If you really want to "roll your own" secure communications scheme, you're first going to have to familiarize yourself with the theory of cryptography and the various available algorithms. In particular, to implement an effective hybrid cryptosystem, you're going to need:
an authenticated public-key based key agreement protocol (preferably something based on the Diffie–Hellman key exchange, and thus providing forward secrecy) to provide the client and server with a temporary shared key;
an authenticated symmetric encryption algorithm, to provide a secure channel between the client and the server using the shared key; and
if the data is transmitted as discrete messages within the secure channel, a communications protocol capable of detecting message replay attacks (e.g. through the use of sequential message numbers).
While all of these can be implemented using only a few discrete crypto primitives — a block cipher (e.g. AES), a public-key encryption/signature algorithm (e.g. RSA), and possibly a hash function (e.g. SHA-256) and some way to do modular exponentiation for Diffie–Hellman — it's generally easier to use protocols and schemes that you crypto library already implements a high-level interface for.
Unfortunately, the most widely implemented schemes also tend to be the older ones, which may be slower and have weaker security guarantees than more modern schemes. That said, if I had the choice (and keep in mind that I'm by no means a true crypto expert), here's what I'd pick:
If the client needs to authenticate itself using a password, I'd pick SRP for the key agreement protocol. If both sides have public signature keys known to the other, the problem is somewhat simpler, and could be handled simply by using raw Diffie–Hellman and then having both parties sign the D–H shared secret, or by using something like STS. (Note that, even with SRP, you may still want the server to authenticate itself to the client using something stronger than just knowledge of the client's password verifier.)
For the signature algorithm, any of RSA (with proper padding), DSA or ECDSA should do, as long as the key length is sufficient. (What counts as sufficient depends on the algorithm.) Where hash algorithms are required, I would, for now, use SHA-2; once the SHA-3 standard is finalized, it should also be a valid choice.
For the symmetric encryption part, I'd go with SIV (RFC 5297) for maximum fool-proofness, or with GCM if speed is critical or "on-line" encryption of large messages is required (and you don't have to implement it yourself). OCB could also be an option, if the patent exemptions are enough for your purposes, and EAX is perfectly good too, if not the absolute fastest. See also How to choose an Authenticated Encryption mode.
Generic composition of a block cipher (e.g. in CTR mode) and a MAC would also work, as long you make sure to apply the MAC to the message after encryption (end verify it before decryption). Any decent MAC should do, but HMAC is generally a safe and robust choice, if you have a good hash function available and don't need extreme speed. (If you do, a fast Carter–Wegman MAC like poly1305-AES may be worth considering.) Try to avoid the old CBC-MAC if you can; CMAC is much better.
In any case, I see no good reason to choose anything other than AES for the underlying block cipher at the moment, although it's always good to design your protocol so that new cipher options may be easily introduced (and old insecure ones deprecated) in the future.
To derive the symmetric encryption key(s) from the D–H / SRP shared secret, you'll generally need a key derivation function; HKDF (RFC 5869) is a good choice for this job, especially if you already use a hash function anyway. (It shouldn't be used — alone, at least — for hashing passwords, though; for that, you need a key-stretching KDF like PBKDF2 or scrypt.)
Also, as noted, I would design my communications protocol so that all messages carry a sequential message number and explicit sender/receiver designations, and so that messages with duplicate message numbers or invalid designations are discarded as forgeries. Conveniently, these message numbers + designators can also be used as nonces for the symmetric encryption protocol (possibly after hashing, if they would otherwise be too long).
These message numbers and designators don't necessarily have to be encrypted (although they do need to be authenticated as "associated data"); not encrypting them has the advantage that you can immediately reject any messages with bogus numbers or designators, even before attempting decryption.
Finally, always keep in mind that there may be exploitable gaps in what I've suggested above, or in the way you choose to apply my suggestions. Make sure to get as many competent security experts as possible to review your protocol and implementation before you use it for anything actually important.
As for specific crypto libraries or APIs in the various languages you mention, I'm not particularly familiar with those, and thus cannot offer detailed advice. Just look at the documentation of standard crypto libraries and see what they offer.
Create Signature for the both end client and server.
$key='any key';
$timestamp='current time stamp'
$url='url to access the file'
$signature = $sha1($key,$timestamp,$url);
use this function at both end and match the signature value and then let it access the data.

Client Side Only Cookies

I need something like a cookie, but I specifically don't want it going back to the server. I call it a "client side session cookie" but any reasonable mechanism would be great.
Basically, I want to store some data encrypted on the server, and have the user type a password into the browser. The browser decrypts the data with the password (or creates and encrypts the data with the password) and the server stores only encrypted data. To keep the data secure on the server, the server should not store and should never receive the password. Ideally there should be a cookie session expiration to clean up.
Of course I need it be available on multiple pages as the user walks through the web site.
The best I can come up with is some sort of iframe mechanism to store the data in javascript variables, but that is ugly. Does anyone have any ideas how to implement something like this?
FWIW, the platform is ASP.NET, but I don't suppose that matters. It needs to support a broad range of browsers, including mobile.
In response to one answer below, let me clarify. My question is not how to achieve the crypto, that isn't a problem. The question is where to store the password so that it is persistent from page to page, but not beyond a session, and in such a way that the server doesn't see it.
You could use JavaScript's localStorage object. The Dive Into HTML5 ebook has an excellent chapter on it. I think the chapter also mentions some possible work-arounds for browsers which to don't support localStorage.
For what you are looking for I would say that javascript is the best you could do.
You can retrieve the encrypted data onto the server and decrypt it using javascript on the client side. No transmission of password, no secret for the user.
It depends which encryption algorithm you are using but there is libraries for that (for example Stanford Javascript Crypto Library)
(but I don't understand why are you talking about cookies)
If you are interested in the storage aspect rather than the cryptography aspect, perhaps you might consider Thomas Frank's session variables

Categories

Resources