A safe way to send and show passwords to client - javascript

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.

Related

Suitability of scrypt for password authentication in the browser using Dart

I've written a Go server with custom binary websocket protocol, and a Dart client. User authentication on the server employs scrypt and the recommended parameters N=16384, r=8, p=1 (with salt of length 16 and generated key length of 64), my i7 desktop takes maybe a second or two to crank through authentication on the server side. That's compared to practically instant, say, SHA-512 authentication.
I had trouble finding scrypt implementations for Dart and while this one works, generating the same hash with the same parameters in a browser (Firefox) takes too long to practically complete. I can get it down to a handful of seconds on the same machine using N=1024 and r<=8 but if I settle on that for compatibility, on the server side, the authentication time is for practical purposes instant again.
Scrypt is great on the server side but I'm wondering if its practical for a browser client. Admittedly I haven't seen any/many examples of people using scrypt for browser authentication. Should I persevere and tackle the performance (e.g. maybe using other javascript libraries from dart), or is this a basic limitation at the moment? How low can you wind down the scrypt parameters before you may as well just use more widely available, optimised crypto hashing algos such as SHA?
Use HTTPS. If you're hashing the password in the browser and then sending the hash to the server for comparison, what's to prevent an attacker from simply sniffing the hashed password and hijacking the session by sending the same hash himself?
Even if you come up with an encryption scheme to prevent that, the attacker could simply inject an additional <script> tag with a keylogger via a MITM attack to steal the password before it's encrypted.
Basically no matter how you cut it, you have to use HTTPS to ensure that your communications are not sniffable and no MITM attack has taken place. And once your connection is already secured over HTTPS, which is encrypted with a (minimum) 128-bit key and would take longer than the known age of the universe to crack, you might as well just use the HTTPS connection to send your password and doing additional encryption of the password client-side is probably not necessary.
#maaartinus ...
I've never thought about not using HTTPS. I'm curious if offloading the password-based key derivation overhead to the client makes any sense.
If I may, I can come at this problem from non-Web direction and come back to the browser-use case. Way back when, I worked with EFT*POS security standards and working with secure communications for financial transactions. For example; the credit-card machine in the supermarket. Just establish my grounding on this topic. That said, I think the original question HAS be covered comprehensively. I decided to add a comment to enrich the conversation on this area (it is quite topical).
The procedure is about the a conversation between the terminal (iPhone, smartphone, browser, etc). Premise: you naturally don't want anyone sniffing your username/password pairing. Assume your typical web page or login screen at work. Over the Intranet, LAN, WAN and VPN what every you type is dispatched from your keyboard to the host. These links may already be encrypted these days. The WWW web on the Internet has two main options: HTTP (clear text) and HTTPS (encrypted) via the browser. If we just stick with the (username, password) pair.
Your terminal (such as browser or mobile) needs to be "trusted" by the host (server, phone company, etc).
There's a lot of standard stuff you can (should do) first; and get creative from there-on. Think of it as a pyramid. On the bottom are things you can do on your PC. That's the base of the pyramid. And there's loads of good information about that (e.g. Electronic Frontier Foundation, EFF), it is about protecting yourself, your data (intangible property) and your rights.
That said here are a few points to consider:
Everything sent via HTTP is clear-text. It can be read and copied.
A hash sent over clear-text can be decoded to get the password. It is just maths.
Even if you use scrypt or another method the hash is decodable -- Given enough time.
If you're on the web, any hash implemented in the browser (terminal/client), is transparent to anyone who can load the web page and javascript code [pointed out by ntoskrnl above.
HTTPS on the other hand, sends Everything-as-a-hash. In addition the hash used is negotiated is unique to the conversation and agreed at session-completion time. It is a slightly 'better-er' hash over the whole-of-the-Message.
The main thing making it better-er in the first instance, is the negotiation. The idea overall is that message hashes are based on a key only known to both end-points.
Once again that can be cracked if you have enough time, etc. The main thing making this challenging is establishing the to-and-fro for the negotiations.
Let's back-up a little and consider cryptography. The notion is to hide the message in a way that permits the message to be revealed. Think of this a as lock and key, where the door is the procedure/algorithm and your message is the contents of the room.
HTTPS works to separate the lock from the key in a pragmatic fashion, in time and via process.
Whatever is done in the HTTPS room, stays in the HTTPS-room. You must have the key to enter, poke about and do unwanted stuff. Imho, any extra security should be ONLY considered within a HTTPS space.
There are methods to improve on that foundation. I think of security like a pyramid. about 4 or 5 layers above the base considerations like the transport protocol.
Such options include, ...
SMS authentication number to your phone.
Something like a dongle or personalised ID-key.
An physical message like an s-mail or e-mail with an authentication Number.
anything you come up with.
In summary, if your need say make it safe; there are many things that can be accomplished. If you can't use HTTPS, hashing password(s) locally needs to be managed extremely carefully. Hashes have vulnerabilities. When you are not using HTTPS, anything you can do in the browser is like wet-rice-paper trying to stave-off a sword.

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.

Encrypting pass in javascript with a key, then retrieve the original password (as securely as possible)

I would like to encrypt and save a user password in a database, all this with javascript, and later decrypt it. I would like to use a key to encrypt/decrypt all passwords. I was thinking about storing them in an sqlite database.
Do you think this way the database will be secure in case of theft? I guess it will highly depend on the algorithm and implementation.
Can you point me in the right direction to any library that has this functionality, allows me to encrypt/decrypt?
Can you recommend me a library to handle sqlite db. with javscript?
I would normally do all this with some webscripting language without decrypting the pass, but I need to do this with js. and I am fairly new to the language. So any advices would be appreciated.
Thanks!
Client side code should not be used for securing a connection, as the Javascript code itself was loaded from the insecure connection and is thus prone to tampering.
Just load your script and do all sensitive communication through https and and you should be fine.
If you encrypting/decrypting anything, it should be done on the server.
A hacker can view the source code of the JS to figure out the hashing algorithm, and assuming they're using a packet sniffer or similar piece of software, compare that algorithm to the data sent by the user.
For what you want to achieve, you could connect to the server with HTTPS, and send passwords and receive authentication notices to/from the server via xmlhttprequest.
I do not know of any algorithms for doing everything on the client, probably for the reasons listed above. There are plenty of PHP hashing algorithms however. This site may be of use: http://phpsec.org/
Edit: (Read your comment on the OP) Doesn't Firefox offer this functionality already? In any case, saving passwords made on the local machine can be stored on the local machine. When a page is revisited, you could auto-fill the related password fields. The only security threat there is if the host computer is compromised. I don't know any code samples for this though.

Security considerations for my personal password manager

My security knowledge is kind of limited but I might learn something.I´m planning to create an ajax application where I encrypt/decrypt passwords client-side with a typed master password
using a javascript AES library and then send/retrieve the encrypted data to/from Google App Engine(user authenticated). I actually found a project with the same idea: http://code.google.com/p/safety-vault/
In my mind as long as I keep my local computer secure (keyloggers) this should be quite secure or am I missing something?
As long as you use SSL for the webapp, this should be fine. Without SSL, an attacker could modify the page to insert some Javascript that sends them your password when you type it.
You might want to reconsider your threat model, though. Do you trust the server? If not, you shouldn't trust it to not send you a page that captures your master password when you enter it. If you do, you shouldn't have any qualms in sending your master password to the server.
There is a problem here, as I assume at some point you're going to have to send your master password to the browser client? If you have the master password, then you can decrypt the stream you send...
Use HTTPS, it's what it was designed for.
You effectively are trusting Google App Engine employees, and transitively, the entire trust chain behind them, to not steal your passwords. Encrypting client side doesn't mean anything if you are executing JavaScript code the server sends you, furthermore if you have no HTTPS implemented properly, it's trivial for someone to do a man in the middle attack and steal your passwords as they are transmitted. Just store the passwords locally or encrypt them with a well known tool like GPG and upload them.

Client-side hashing/salting over HTTPS

I'm wondering what the serious issues are with the following setup:
Username/password login scheme
Javascript/ajax requests the salt value from the server (we have established in previous questions salt is not a secret value)
Javascript preforms an SHA1 (or otherwise) of the password and salt.
Javascript/ajax return the hash to the server
The server applies another salt/hash on-top of the the one sent via ajax.
Transactions are over HTTPS.
I'm concerned about problems that may exist but can't convince myself that this is that bad of a setup. Assume that all users need javascript enabled as jQuery is heavily used on the site. It's basically attempting to add an additional layer of security to the plain-text of a password.
As always: be very careful about designing cryptographic protocols yourself.
But that being said, I can see the advantage in the scheme. It will protect against the password being revealed through a man-in-the-middle-attack and it will ensure that the server never sees the actual password, thus preventing some inside attacks. On the other hand it does not protect against man-in-the-browser, fishing etc.
You might want to read through RFC 2617 about HTTP Digest access authentication. That scheme is similar to what you propose.
All that effort of passing salts and hashes between the client and server is already built into the underlying HTTPS/SSL protocol. I would be very surprised if a security layer in javascript is going to help very much. I recommend keeping it simple and use plaintext over SSL on the client-side. Worry about encryption on the server-side.
This doesn't add any additional security. The JavaScript code is present in the client, so the hashing algorithm is known. You gain nothing from doing a client-side hash in this case.
Also, there's no reason why the client should know about the hashing salt. It actually should be a secret value, especially if you're using a shared salt.
I'll 100% disagree with the accepted answer and say that under no circumstances should an original password ever Ever EVER leave the client. It should always be salted and hashed. Always, without exception.
Two reasons...
. The client should not be relying that all the server components and internal networks are TSL. It is quite common for the TSL endpoint to be a load balancing reverse proxy, which communicates with app servers using plaintext because devops can't be bothered to generate server certs for all their internal servers.
. Many users are pathologically inclined to use a common password for all of their services. The fact that a server has plaintext passwords, even if only in memory, makes it an attractive target for external attack.
You're not gaining anything. There's no point to a salt if Joe Public can see it by clicking View > Source, and the old maxim about never trusting client input goes double for password hashing.
If you really want to increase security, use a SHA-2 based hash (SHA-224/256/384/512), as SHA-1 has potential vulnerabilities. NIST no longer recommends SHA-1 for applications that are vulnerable to collision attacks (like password hashes).

Categories

Resources