5

I made a login system. The user can login by:

  • using a normal email / password (bcrypted).
  • using a service like facebook, gmail, etc.

So far so good. Now I want to store sensitive information (ftp credentials) in the database in a secure manner. This is very easy for the first users: when the user logs in with their email/password, the password gets hashed with one (default) salt to check for authentication, and with another salt to obtain a strong hash X.

Then I use this hash X as a password to encrypt the sensitive data that the user wants to store. In this way, full access to the code and database does NOT compromise the user's data. *

Is there a way I can achieve a similar security level for the users that log in with a service that inherently have no password to begin with? Highly recommended to be a server-side hassle and not adding extra complexity for the user. These are all the options I can see with their problems:

  1. Require for every user, even Facebook/Gmail/etc, to write and remember a password. This is agains the principle that made me integrate those services in the first place.

  2. Use a server-side, site-wide unique encryption password. I want to protect against full access to the code and database, so no one (including developers/admins/etc) can peak into this private data.

  3. Use some user-specific data. This would be the user Facebook's id, for example. It could be retrieved by simply doing a search for their email in fb, thus not secure.

Francisco Presencia
  • 675
  • 1
  • 6
  • 20
  • You could run their Facebook Connect ID, suffixed with some site-specific secret "pepper", through bcrypt to generate a suitably random key to encrypt their FTP password (or for use as the FTP password.) Your security problem then moves to mean you have to keep your database safe, and the pepper secret. – John Deters Jan 10 '14 at 00:01
  • 1
    I want to protect user's data from everyone, including admins or/and a thief with the database. I would rather prefer a user-specific salt instead of a *pepper*, it should make things more secure against a rainbow table on the ids. I don't normally store the user's id from facebook. However, I do store the email. In case of db theft, that'd be known, and a simple email search should yield back the user's id, thus I consider the id as an invalid *secret*... – Francisco Presencia Jan 10 '14 at 00:14
  • Theft of the DB would be useless without the pepper, as it would serve as your system's secret key. Of course the attacker could steal it as well, because you'd need it on the same system that runs bcrypt. You could simply encrypt the data with a symmetric algorithm instead of a pepper to achieve about the same level of security. (Probably better, because admins understand a "key" needs to be kept secret, but they won't understand a pepper does, too. ) – John Deters Jan 10 '14 at 16:20
  • I am looking more for some self-containment system that doesn't require a general verification system, but rather is user-dependent. As I specified in the edit, I want it to be secure even for full read access to the code/database, in a similar fashion as how `bcrypt` works. – Francisco Presencia Jan 10 '14 at 21:51
  • 2
    You are asking to generate secret data from a single, non-secret source. It can't be done under those exact conditions. You need a 'source of secrecy'. You can try to squirrel a key away in a config file, perhaps encrypted with yet another key, or you can move some aspect to a different, secure machine, such as an HSM, to host your encryption and keys. But you can't create a recreatable secret out of a finite set of data and expect an attacker to not be able to replicate your feat. – John Deters Jan 11 '14 at 00:20
  • The compromise of either salt would lead to the ability to determine the user's password.The fact you store the hash from two separate salts won't change this fact.Your user's passwords still are vulnerable to a single brute force attack. I would say that your better off protecting the account and the contents by allowing these Facebook/Google/Microsoft protect their user's account.This allows your users to decide how best to protect their account with you. Most providers support authenticators allowing additional protection. You being compromise still keeps their ftp information protected. – Ramhound Jan 11 '14 at 01:42
  • @Ramhound, how would the compromise of the salt and hash allow for bruteforce attack? bcrypt uses hash stretching, which means that each hash takes 0.1s in my system (slow). That means that, even in a 100 times faster system it'd take years to find the original hash of *one* single password providing it's at least 6 digits with alphanumeric+symbol. [There's an excellent Q&A already here](http://security.stackexchange.com/q/4781/9161) – Francisco Presencia Jan 11 '14 at 11:09
  • @FranciscoPresencia - If either salt was known they would be able to brute force the user's password because all you did was hash it twice with two separate salts. The simplest of the passwords will be brute forced. – Ramhound Jan 11 '14 at 11:47
  • [You cannot just bruteforce bcrypt efficiently](http://rambling-finn.blogspot.com.es/2011/08/better-protection-against-gpu-brute.html), even with GPU... – Francisco Presencia Jan 11 '14 at 11:53
  • @JohnDeters, your comment could be perfectly the accepted answer so future visitors (as myself) have a clear answer, if you want. – Francisco Presencia Apr 10 '14 at 13:19

2 Answers2

2

You are asking to generate secret data from a single, non-secret source. It can't be done under those exact conditions. You need a 'source of secrecy'. You can try to squirrel a key away in a config file, perhaps encrypted with yet another key, or you can move some aspect to a different, secure machine, such as using a Hardware Security Module (HSM) to host your encryption and keys. But you cannot create a re-creatable secret out of a finite set of data and expect an attacker to not be able to replicate your feat.

John Deters
  • 33,650
  • 3
  • 57
  • 110
0

Your question seems to be: "I want to securely store user passwords, but in a reversible manner." This basically means that you want to implement DRM (on your server), which is basically impossible, especially in a common-use-library scenario.

You would need a separate, disconnected server/service to store user credentials, and that server would only be accessible via an API that would handle requests like:

  • "Save $ftp_user_and_password for $user_id"
  • "Upload $these_files to FTP for $user_id"

The server would need to be otherwise be completely disconnected from your app (and not accessible to other incoming requests). This is similar to — for example — credit card handling.


Additionally: you mention that your real need is to protect user-provided FTP credentials.

In addition to other safeguards, it would be much more secure to force your users to create a new FTP user for your service, using credentials that you generate on your server ("Please make a new FTP user account with username=my_service, password=long_random_string").

This means that user's won't simply give you their "common" FTP password (that they also likely use for other accounts) that would possibly result in a lot of problems should your data be accessed by a malicious 3rd party — you can simply email all your users and ask them to revoke your service-specific FTP user account access. (If you lost their "common" password, many (certainly more than zero) users would likely not change their common (FTP) password because it would be too inconvenient.)

You would still need to think about protecting the service-specific password, but worst-case scenario would be much more manageable.

Joel L
  • 1,427
  • 11
  • 12