currently we're working on a small application where we store a bunch of JSON data coming from a JS-based graphing editor (think of a spiced-up version of this) in a Rails-based backend. We want to allow users to store the data encrypted (AES, RSA, whatever), where we as the application maintainers have no possibility of decrypting what's lying in our DB - given a strong password of course. There's no user account management, nothing. People are only able to create and edit their graphs via a secret link, nothing more nothing less.
The password would then be needed to encrypt / decrypt the graph coming and going to the DB before editing or saving the current state. Now, the conceptual questions we're facing right now are the following:
Do we store the password throughout the session? If not the user would have to enter the password every time he refreshes the browser or wants to save the current state of his graph into the DB. Uncomfortable...
If - from a software engineering perspective - this is applicable: Where does this kind of information gets stored in general? What options apart from cookies do we have?
If so - would we have to store the plain password or is there a way to somehow encrypt the password so that in case of a stolen cookie an attacker would face a more difficult game getting the password?
Many times, security is a balance, and this is one such case.
Considering your requirements (webapp with no user mgmt backend), I think you have two options:
You don't store the password, but then user experience is worse. As you said, any refresh will need the password again from the user.
You store the password client-side (see below how), one reasonable place would be SessionStorage. This way it is comfortable and would work as any user would expect: it 'just works' until the user closes the browser, but not afterwards. Obviously this has the very real risk of the password being present in the browser in some form. It is available to any Javascript (consider xss) and you can't prevent it from being cached to disk (no matter what you do, consider hibernating the pc, etc). In general, this is an antipattern, but it's not that simple. Security decisions should be risk based.
This is a decision you have to make based on risks specific to your usecase. What is the data, what is the likelihood of an attack (what did you do to attain reasonable assurance that your code is secure), what is the impact (what will you lose if the password is lost, including things like loss of reputation too). Also would your users really hate the product if they had to enter the password all the time? Only you can anseer these questions.
Encrypting the password on the client doesn't make sense, thr attacker would have everything to decrypt it. However, there might be a benefit to hashing it, and it might be a bit surprising at first. If you don't actually store the password but some kind of a transformation, then whatever you store will be the password, so seemingly it doesn't make sense. The reason it still does is because people tend to reuse passwords, so if you derive a key from the password with say PBKDF2 and store that as the key, it is better, an attacker can't have the actual password from the browser (but they can still access the data if there is a compromise, say xss).
So if (and only if) you accept the risk of storage explained above and also the risk associated with javascript crypto, you should
derive a key from user password with a proper key derivation function like pbkdf2
store that key as the encryption key in SessionStorage
Related
I am writing a trading application using Node & Express for the backend. Each user will have their own login for the application itself, but in order for it to be useful the application also needs to login to the user's brokerage account.
The brokerage account in question has a REST API in which you POST the login and password for that system. That API does not offer SSO or OAuth as an option for authentication. The only means to authenticate is POSTing the uid and password.
So there are two logins involved here: one to my application, and another completely separate login to the brokerage account. Each of those logins uses a different user ID and password.
The problem I'm having is figuring out how to store the password for the brokerage account. I understand that storing a password at all is a bad idea. But if all I store is a salted hash of the brokerage password, I wont be able to reverse that and get the actual password back. Hence, my application won't be able to login to the brokerage account unless the user enters that password again.
(As an aside, there is another program that does this. https://dough.com requires the user to login to dough, and then you also have to login to TD Ameritrade. That logging in twice is what I'm hoping to avoid.)
Is there a reasonable and secure way to store a password for this 3rd party API so that my app can login on the user's behalf without forcing the user to submit the password every time they use my app? I understand there are big security risks here. If the answer is no, then I won't.
Edit & Obligatory - Really the solution is to not do this. While technically possible, it will almost certainly not be implemented correctly & will expose your users' passwords.
Yes there is, but it's not incredibly easy & implementation is key. The JavaScript OpenPGPJS library is what you want.
In order for a somewhat secure system, your backend cannot be allowed to decrypt the password. This is where the JS library comes in, which provides PGP crypto via the browser.
You can base the PGP password off of the user password, or make them provide a new one for decryption. Alternatively, you can generate random keys for the password encryption then create a master key with access to the random ones - encrypting the master with the user input.
Whichever method you go with you will either need to have them enter the password in order to decrypt the record when needed, or add their password into their local session. The former is secure and the latter has obvious security implications.
Simple string encrypt using a password as provided by the examples:
var options, encrypted;
options = {
data: 'Hello, World!', // input as String
passwords: ['secret stuff'] // multiple passwords possible
};
openpgp.encrypt(options).then(function(ciphertext) {
encrypted = ciphertext.data; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
});
Decrypt:
options = {
message: openpgp.message.readArmored(encrypted), // parse armored message
password: 'secret stuff' // decrypt with password
};
openpgp.decrypt(options).then(function(plaintext) {
return plaintext.data; // 'Hello, World!'
});
I think you have a few options, and the decision you choose should depend on the risk you want to take. If it is financial data as you hinted, I think the decision should clearly be not doing any of this.
One option is to store the 3rd party API password encrypted on your server with a key derived from the user's local password. As you don't store your user's local password, you can only decrypt the 3rd party API password upon user logon when you have his local one, and from there if you want to make future calls to the API impersonating the user, you will have to keep the plaintext version of the 3rd party password in server memory (the user's session). I think that while in some applications this could probably be a viable option, for financial data this is unacceptable.
Another thing you could do is encrypt the 3rd party API password in Javascript as Dave Lasley described in his answer. While that could work, it adds a lot of complexity, and as he also pointed out, implementation would be key. It would be hard to get this right and maintain over time without introducing vulnerabilities. Also Javascript crypto has its problems, the best practice is to not do cryptography in Javascript. You would have to keep the 3rd party API password in Javascript memory, which is a very weak control, any single XSS would be able to steal it from there (any other browser store is even worse than a Javascript object in memory). Also the 3rd party API would need to support CORS from your domain (or * obviously).
My take is that pretty much the only good way to do this would be a careful implementation with OAuth2. If the API doesn't support that, then you should not do this at all unfortunately.
TL;DR - Storing user's login password for web app in memory in JS for use in client-side encryption of user's data: yea or nay?
I'm working on a web application where users can store notes in the cloud. Users have a password to login. In addition, users can elect to encrypt notes using a password. The notes are stored encrypted in the cloud, meaning only the user can decrypt them (and notes are lost if their password is lost).
For user convenience it would be better to use the same password for account login and for note encryption, and, upon login, to store that password in memory in a JS variable so they don't have to re-enter their password every time the application needs to encrypt or decrypt anything (for instance if they update a note).
Is this insecure? Yes, an attacker with access to the user's machine could do a memory dump, or insert breakpoints into (uglified) JS, etc., and obtain the password. But an attacker with access to the user's machine could do this anyway: in order to log in at all there is necessarily a point where the user's password is accessible in plain text in my application's JS.
So it seems okay to me - no more insecure than not storing it. Thoughts?
Yes, the JavaScript variable will be protected by the Same Origin Policy preventing other domains from accessing this data.
Consider storing a salted hash of the password as a JavaScript variable and then using this hash to encrypt and decrypt data from the cloud. This will protect against a local attacker from querying local variables on somebody else's computer in order to get the password (say they've left their screen unlocked while they grab a coffee). This is a slightly higher risk as an attack which involves stealing the session (which is just as easy to do on an unattended computer) as the password may have been reused on other sites. You don't want your site to be the weak point of an attack gaining access to another user's Gmail, bank account, Facebook, Twitter, etc.
Also consider key stretching in order to make your encryption key "strong enough". As the encryption key is the password (called Password Based Encryption), this needs to derive a key of at least 128 bits of entropy, which is more than your average user's password contains.
Other things to consider in your design:
Use TLS to secure all communication over HTTPS.
For any session cookies set the Secure Flag and HTTP Only Flag if possible.
Use HSTS to ensure future connections from repeat users are HTTPS only.
It is only secure if you use SSL/TLS, because otherwise an network-based attacker may use a man-in-the-middle attack to change the client side JavaScript code in a way that sends the password directly to the attacker including all notes.
If you have that and can effectively prevent the attacker from adding more JavaScript (e.g. through XSS), you should be fine.
Well if only the user can access their own passwords, then it should be fine. But if the cloud is not secured (as you said it is client side) I don't think it would be best. You should use a server side password system instead. I am a full time white hat hacker and anything client side can be easily stolen. If all you are storing are notes and not credit card info, it should be fine.
I'm experimenting with PouchDB and client-side Javascript. The example on the PouchDB site works great for me: http://pouchdb.com/getting-started.html. My question is, is there any way to obscure the username and password when I connect to the remote server? The code in question:
var remoteCouch = 'http://user:pass#mname.iriscouch.com/todos';
This is all client-side JS and publicly viewable. I'm stumped on figuring out a way around it.
When you're communicating between servers you can use SSL to remain secure. The client and server establish a secure connection before sending any data about the request (i.e. the file name, the basic authentication creds, etc.).
As far as what lives on the client side, it's more of a question of how secure do you want to be. Since everything is JavaScript, especially so with PouchDB, you have to settle for one of two things
Having a fancy switch that shows you menus or hides menus
In this scenario you have a main screen with all the important menus. The user either supplies the right password, which takes them to that screen, or the program says "Error incorrect username or password". But since it's all in JavaScript, anyone with enough knowledge of your system could say something like MyApp.User.isLoggedIn = function() { return true; };.
Encrypt what you need
If there is sensitive data on the client side, you can ask them to supply their password and encrypt the sensitive data using that password. Depending on the payload, it may or may not be too performance intensive. You might have to implement your own sessions in this case so you don't end up keeping that password or sensitive data around in memory. Then all Eve would have to do is go to the JS console and hit console.log(MyApp.User.password);. Even though the password is hashed and salted (or should be), Eve likely still has access to the hash function and salt.
Good luck! Would love to hear what you come up with.
If the username and password are to be provided by the user, you can present them with a login prompt and use a secure CouchDB session cookie. The cookie is tamper-proof and will be deleted when the browser session ends or you explicitly delete it.
I made fire fox add-on using java script. I want to give password protection to this add-on. Where can I store the user password permanently ? How can I do this?
The best solution would be to store on an external storage. Just like websites. You send the authentication data, server checks for user and returns true or false. There are a few problems with this. If you want to restrict parts of add-on for non-registred users, that's not possible. The whole code is available to the user and he can modify it.
If you create a website specific add/on search for a data (most likely in the cookies and preferences of the website) that is a secret, unpredictable, unique and uniform for a single user. You can hash that and use it as a password. Along with the username of that specific website. This way you can avoid registration.
Server communication trough HTTP is not too secure, but hey, most websites still use it.
If you don't have an external server available, you can use local storages like a SQLite, or i you have a single password you can use the preferences which are also available under about:config. But these are far from permanent. It's there until the user reinstall operating system, which unfortunately is quite common.
If you want closed source to hide storage mode, hash generating or something like that XP-COM components might help you but I don't recommend because it's really hard to maintain (all versions on all platforms).
If the password is required to authenticate the user to a server then you should use nsILoginManager to store it. The password will be stored encrypted on disk if the user defines a master password. If you want to protect the extension's user interface from the user then it doesn't matter where you store the password - this kind of protection works only against inexperienced users. E.g. you can use Preferences to store it.
given the following scenario: We have a html form for changing an account's password. It looks like this:
CurrentPassword: __________________
NewPassword: __________________
NewPasswordAgain: __________________
We want to send this request via an ajax call. If we send it and we leave our computer (without logging out and staying on the exact same page) someone could open the webkit inspector (or firebug) and see something like this:
http://cl.ly/3y213W1q0U2y2e251k0O
What would be your solution for making this more secure? Is it even possible using an ajax call here or would it be better to use a "normal" html form which reloads the whole page after sending?
Using a "normal" html form has the same problem, as packet sniffing could reveal the same data in a POST or GET header just as easily.
The best solution I can think of is to encrypt the password user-side via javascript. You don't really have to worry about the "what if the user has javascript disabled?" case since, in that case, the AJAX request won't go through either. Obviously this may have ramifications regarding how you store the password, but it will allow you to continue to use AJAX requests for the password update.
The author is not interested in encrypted connections here. He may as well be doing that already. What he wants is to be able to hide the password (and username) from any one who has an access to the computer, and can open the inspector tools to view the networking that occurred on the page.
One of the simplest things you could do is to refresh the page in case the authentication succeeded.
Something that you should do is to refresh the page whenever the user pressed "log out". This should clear all previous network data.
The less good options are about encrypting, obfuscating and hashing the password prior to sending it.
Hashing the password on client-side is not ideal because this prevents the use of hashed passwords with keys on the server-side (think HMAC). HMAC'd passwords are the best, because the key is kept on the filesystem whereas the salt is kept on the database. Cracking the password hash requires a rather solid access to the system.
Obfuscating and encrypting the password can be reversed. If someone sees a login request on the Webkit Inspector, he might be very interested in spending the time to undress your defenses.
I highly recommend refreshing the page at some point to avoid the problem entirely. Other options do not seem as good.
Encrypt the password on transport and make sure the calls you are making are being done over SSL!
To make this secure without using SSL, hash the passwords on the client using SHA-2. While that will protect the password itself, it won't protect someone from sniffing the hashed password. So you can't simply authenticate with the hashed password, either.
One way to do this is to use a server-generated random salt when authenticating. To authenticate, the client requests salt from the server, then hashes the password once (in order to match the hashed version stored on the server), then hashes again using that salt that it received from the server, then finally authenticates using a second ajax query with the salted-hashed password.
The server will authenticate only if this matches its own stored hashed password, hashed with the same salt it previously provided the client.
This way, it is impossible for someone to authenticate using the simple hashed version of the password. Since each salt provided by the server is valid only once, it would be essentially impossible for someone to intercept it and authenticate. (They would have to intercept the salt request, and then try to authenticate before the legitimate client could, all the while spoofing their session).
This protects users' passwords without using SSL, prevents logging in using data intercepted while the legitimate user is authenticating, and is fairly easy to implement. Of course there is no substitute for SSL as far as protecting the actual data on your site, but for a lot of typical web sites where there's not really any sensitive information, you should be more concerned about preventing theft of your users' passwords since people use the same password so often. This addresses that problem.
Note that this also does nothing to prevent session hijacking, but you can minimize the risk and damage of this by doing things like including browsers-specific information with the users's session, and allowing only a single active session at once, and requiring re-authentication to change email address or password.
Depending on the level of security you need, you could use RSA and public-key cryptography to encrypt the password within the browser prior to sending the ajax request. On the server-side, you would decrypt the passwords and process them as normal.
Of course, you would also need to be careful to delete any variables used to hold the entered passwords, and I am sure there are other security holes in this, but encryption will at least offer you some large degree of protection against that sort of attack.
Here's one library I found with a quick search. (disclaimer: I have not tested this, but it looks pretty good)
Lastly, I would strongly recommend that you transmit all login information via SSL. This adds an extra layer of security on top of the whole browser session between the browser and your server.