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.

10
  • 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. Commented Jan 10, 2014 at 0: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... Commented Jan 10, 2014 at 0: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. ) Commented Jan 10, 2014 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. Commented Jan 10, 2014 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. Commented Jan 11, 2014 at 0:20

2 Answers 2

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.

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .