Storing user and password in a database

2019-02-03 12:48发布

问题:

I am creating a software with user + password. After autentification, the user can access some semi public services, but also encrypt some files that only the user can access.

The user must be stored as is, without modification, if possible. After auth, the user and the password are kept in memory as long as the software is running (i don't know if that's okay either).

The question is how should i store this user + password combination in a potentially unsecure database?

I don't really understand what should i expose.

Let's say I create an enhanced key like this:

salt = random 32 characters string (is it okay?)
key = hash(usr password + salt)
for 1 to 65000 do
  key = hash(key + usr password + salt)

Should I store the [plaintext user], [the enhanced key] and [the salt] in the database ?

Also, what should I use to encrypt (with AES or Blowfish) some files using a new password everytime ? Should I generate a new salt and create a new enhanced key using (the password stored in memory of the program + the salt) ? And in this case, if i store the encrypted file in the database, i should probably only store the salt. The database is the same as where i store the user + password combination.

The file can only be decrypted if someone can generate the key, but he doesn't know the password. Right ?

I use Python with PyCrypto, but it's not really important, a general example is just fine. I have read a few similar questions, but they are not very explicit.

Thank you very very much!

回答1:

Crypto is hard to get right, it's good that you're asking questions.

Storing passwords: Passwords should be hashed using a key stretching algorithm. Typically, you want to use a library rather than implement it yourself. Key stretching algorithms are designed to chew up processor cycles, so it's nice to evaluate them with nice C code. If you are on a Linux system with glibc, you can use the crypt.crypt module (read man crypt):

import crypt
encrypted = crypt.crypt(password, '$6$' + salt + '$')

This returns an ASCII string which you can safely store in your database. (The $6$ is a glibc extension that uses a key stretching function based on SHA-512. If you don't have this extension, then don't use crypt.crypt). (Edit: The algorithm is very similar to the one you asked about in your question. However, best practice is usually to let a library do that stuff rather than rolling your own.)

Encrypting files: Do not do this yourself. Install GnuPG (or scrypt, bcrypt, ncrypt, what have you). There are a few things that can easily go wrong when you design your own way to encrypt files. These tools use the proper key derivation functions, authentication hashes, and cipher modes without any additional configuration. They're not Python libraries, but executables, so you'll have to write a wrapper that uses the subprocess module.

Passwords in memory: Don't. Once you've checked the user's password against your password database, convert the password to a key using a key derivation function. You can then use the key to unlock encrypted files, but you can no longer use it to get the original password back.



回答2:

If you use a different salt for each user, you must store it somewhere (ideally in a different place). If you use the same salt for every user, you can hardcode it in your app, but it can be considered less secure. If you don't keep the salt, you will not be able to match a given password against the one in your database.

The aim of the salt is to make bruteforce or dictionnary attacks a lot harder. That is why it is more secure if store separately, to avoid someone having both hash passwords and corresponding salts.