Safely store credentials between website visits - language-agnostic

I'm building a website which allows users to create accounts and access the site's content. I don't want users to log in each time they visit the site, so I'm planning on storing the username and password in a cookie -- however, I've heard this is bad practice, even if the password is hashed in the cookie.
What "best practices" should I follow to safely remember of a users credentials between visits to my website?

Don't ever do that. Throwing around passwords in the open.
Safest method:
Store the username in a database, in the same row a randomly generated salt value, in the same row a hash checksum of the password including the salt. Use another table for sessions that references the table with user credentials. You can insert in the sessions table when the user logs in a date you want the session to expire (eg. after 15 days). Store the session id in a cookie.
Next time the user logs in, you get the password, add to it the salt for the user, geterate the hash, compare it to the one you have. If they match open a session by inserting a row in the sessions table and sending the session id in a cookie. You can check if the user has logged in and which user it is by this cookie.
Edit:
This method is the most popular in use on most sites. It hits a good balance between being secure and practical.
You don't simply use an autoincrement value for the session id. You make it by using some complicated checksum which is hard to repeat. For example concatenate username, timestamp, salt, another random salt, and make an md5 or sha checksum out of it.
In order to implement a feature that involves user credentials in a website/service there most be some exchange of data related to the credentials between the client and the server. This exposes the data to man in the middle attacs etc. Additionally cookies are stored in the users harddrive. No method can be 100% safe.
If you want additional security you can make your site go over https. This will prevent people from stealing cookies and passwords using man in the middle attacks.
Note:
Involving IP addresses in the mix is not a really good idea. Most often multiple clients will come from the same IP address over NATs etc.

You shouldn't need to store the password, just an identifier for the user that your application can interpret to be them.
Things you need to be aware of:
If the cookie is copied, will another user be able to pretend to be that user
A user shouldn't be able to construct a cookie that would authenticate them as another user
A possible solution to deal with these would be to create a one-time key for each user that is changed when they next use the application.
You will probably never be able to remember a user fully securely, so this should only be used if there is no sensitive data involved.

Passwords in any form shouldn't be stored in cookies. Cookies can easily be stolen.
Some browsers already support saving passwords. Why not let the user use that instead?

Storing a hash of the username in a cookie could provide this "remember me" functionality.
However for sensitive areas of the system you would need to know that a user entered the system on cached credentials so that you could offer a username/password prompt before you let them cause any real damage. This could be held as a session based flag.

Related

How to securely encrypt credit card information in a database

I have already read through Saving credit card information in MySQL database? and Storing Credit Card Information.
I'm aware that storing credit card information requires PCI compliance, which is not an easy task.
That is not what this question is about. My question is the following:
What is a secure way to encrypt user credit cards? The simplest and easiest that comes to mind is using a private key and encrypting CC's with that. This doesn't seem very secure because the key has to be stored on the server, and if an attacker can get my database, they can probably get the key too.
What I'd like to be able to do is encrypt every CC using that users password as part of the encryption process. If anyone gets the database, they can't decrypt anything because the passwords are stored as salted hashes. This would work great for transactional purchases - the user clicks "Buy," types in their password as a confirmation, I decrypt their CC and make the charge. Their password is only in memory for the duration of the request, and is never written to disk.
Unfortunately this won't work for what I'm trying to build - a service which charges a recurring fee (say, once a month), regardless of whether or not the user is logged in when I need to make the charge.
Given this scenario, is there a secure way of storing user CC's?
As you need to be able to decrypt, there's always the possibility that the encryption keys leak and you'll lose everything. So you'll never get to absolute security, but you can make it harder for attackers to get to the data.
Nobody but you can really judge what level of security (or obscurity) you should have. This is most likely a function of size of database, visibility etc.
For leaks, unfortunately you'll have to assume that everything leaks and sooner or later (e.g. with brute force attacks on weak passwords) you haven't gained too much when they get out.
Given the last credit card leak scandals - the worst ones had the 3-digit (CVV) number saved with the regular credit card number, which credit card companies explicitly forbid (that's why you'll always have to give it again even if someone has your credit card information on file)
If you don't want to assume the responsibility for holding and processing this kind of data, a good way to go is with an external payment service - let them do the processing and just assert to you that the payment has been processed. You'd have to pay them for their services, but you'd also have to pay for implementing your own solution and for taking the risk.
If you use the password as the salt for the CC encryption, it would be a very effective way of securing the information, however, they would never be able to change their password... If it is changed, then the encrypted data is lost. The bottom line for securing the encryption key is to make it as difficult as possible to find... essentially the more steps you use to hide the key, the harder it is for them to find it... which means it is harder for you to use and program for it. There is no magic bullet at this time to protect everything. (Invent a secure way to keep the key and you will be rich)
As for the CVV number, it cannot be stored as previously mentioned. With each transaction the cc processing company will give the merchant a Reference Number which is then used in each reoccurring payment. This means if the original transaction required the CVV number, then logic will dictate that the recurring payment will also be authorized by the same user who put it in on the first transaction. Therefore, the reoccurring payments will not need the CVV to maintain the same level of security.
You could essentially use multiple servers. Encrypt the cc with a key, but keep that key on a separate encryption server, the is only accessible by a master username and password for windows or whatever OS you're using. This way you're securing your key, setting up a services on the encyrption service to run the card through the encryption and then submit it to the database.
Use php's private/public openssl functions when a user makes a purchase you use the data in memory to make the purchase then you store the information using a public key to encrypt it.
To process billing monthly you decrypt the data using the private key that could be manually punched in or stored in code. If you want to store the ssl key in code and not have to remember it or get it everytime. I would encrypt the key using a salt stored in the configuration variables + buy a yubi key and generate a 32 character password + my own password on top of it. Store the yubikey in a safe place (A safe lol). When you need to process credit cards do it with a script that runs in the background and runs all billing at once. To change the password would require you decrypt all cards and re-encrypt them using the new private/public key, or you may just decrypt and re-encrypt the private key ssl.
Magic :)
You require the card information to be reversibly encrypted. The decryption information has to come from somewhere. You've said the data cannot come from the user, and you don't want it stored at the server, so it must be on separate equipment that is presumably more secure. And if you have the ability to recall that information, so does an attacker who has compromised your system. So presumably the decryption information is not retrieved at the vulnerable host during decryption.
Perhaps consider a third-party service that you can encrypt and send information to, perhaps one that specializes in PCI compliance. It might be able to decrypt the credit card information when you send it a second time and apply a charge, or it might actually store the card information for later use. It might even perform recurring transactions for you.
http://www.authorize.net/solutions/merchantsolutions/merchantservices/automatedrecurringbilling/
I just Googled that, I don't recommend them. But it's an example.
Encrypt the CC information twice. First, encrypt the credit card data based off the user's password (+ salt). Then encrypt the output of that with the server's key.
To access the information, you thus require the user's password (i.e. decrypt using server's key, then decrypt based off password). If the database and server key are compromised, the information still isn't exposed without attacking the user's password first.
It's important that the user's password is for the internal encryption - this allows you to re-encrypt when you change server encryption keys.
When the user changes their password, you also re-encrypt the data. If the user resets their password, then the CC information should be erased (and is lost anyway, as it can't be unencrypted).

Protect PII in web app database by encrypting with public key paired with private key protected by users' own passwords?

Goal:
I'd like to allow users to create questions and collect information from other users in a custom web app (PHP/MySQL in a shored hosting environment) and protect the data collected.
Background:
The default questions that all users answer are general enough that they can not be construed as personally identifiable information (PII), thus limiting my liability to protect it, but users who create their own questions will likely ask for PII which then becomes a liability.
What I would like to do is protect this information in such a way that if either the hosting account or the database were compromised (or both!), the PII would not be recoverable without a significant amount of work, and even then, only a small portion would theoretically be recoverable.
Proposed solution:
Assuming MySQL's built-in AES_ENCRYPT()/AES_DECRYPT() functions are used to encrypt the PII table, the passphrase would need to be stored in the hosting account, so if the hosting account were compromised, the data could easily be read.
Since the users' passwords are well protected (hashed with salt), I'm thinking of capturing their plaintext password during authentication, encrypting it, and storing it in the PHP session until the user logs out.
A public/private key combo will be created for each user with the private key being password protected with the user's password + salt.
Then, when PII data based on that user's custom questions are added to the DB, the user's public key would be used to encrypt the PII that they collected through the app. When the data is read (only when the user is logged in), the data would be unencrypted with the user's private key (which is unlocked with their password + salt).
The benefits I see are:
in the worst case scenario, where servers completely compromised, app code is read to find encryption keys, PHP session files are decrypted to find user's passwords, then entries in the PII table associated with that user are decrypted, then only the PII collected from questions of currently logged-in users could be recovered. Any users not logged in would be safe.
even the DBA or similar wouldn't be able to read the PII.
The drawbacks I see are:
user passwords are stored in a recoverable form while they are logged in.
users who forget their passwords would loose access to their data.
each relatively small bit of data will take up much more space in the DB due to encryption.
My question: Is there a better way to do this?
I see a number problems with this design from a security perspective. First of all passwords must never be encrypted, this is a vulnerability identified by CWE-257.
Further more MySQL's AES_ENCRYPT() is complete garbage for more than one reason. It uses EBC mode, and here is a good example of why this is crap:
Original Image:
EBC Mode (which is what mysql's AES_ENCRYPT() uses):
But if the database where compromised the attacker is going to defeat AES_ENCRYPT() by enabling the query log.
Using the user's password for encryption should be avoided, you should be using a crypgoraphic nonce. If you do use a password make sure you use a String2Key funciton. You must also use CBC or CMAC mode with a random iv. I don't really see how asymmetric cryptography can help. Asymmetric cryptography is very slow, memory intensive. They data that it protects is made less secure when the attacker controls the message because you can compare cipher text messages. This is why an random IV is important, and in the asymmetric world you don't have this level of protection.
Key Generation should look something like:
$key=string2key($base_nonce.$salt.$user_password)
Make sure the output of your string2key function is the same size as your keyspace. So aes 128 needs a 128bit key. Each password should have its own $salt, and the $base is a cryptographic nonce stored in textfile. (An attacker would have to read this file before he can crack the key, if this value is large like 128 bits then its a moot point.) Each message needs its own $iv and this value must also be a cryptographic nonce (similar to a salt). I would generate the $salt,$iv and $base_nonce from /dev/urandom. The IV can be stored in plain text in a column in your database along with the cipher text.
From a legal standpoint even if you build a secure cryptogrpahic system you still have problems with insider threats and if the server is completely compromised, all of the data will still be compromised. This really isn't an engineering problem.
The best defense against a legal threat is a strong Terms and Conditions written by a skilled lawyer.
One concern I'd have is the following. The "any users not logged in would be safe" part is too optimistic. By protecting the private key with the user's password, you open yourself up to various password brute-forcing attacks. Not just for current sessions, but for all. One effective one is to simply enumerate the top 100 common passwords, say, and just try them out against all users. Attacker is bound to uncover some keys. (I'm assuming that you're either storing per-user random salt with the user record, which the attacker can see, or else that you have a secret salt that the attacker was able to obtain through the compromise.)

Storing Twitter OAuth in MySQL

I'm about to add a feature on my website that will post stuff to the users' twitter accounts. I read that storing an "OAuth" token is better than storing their usernames and passwords (which makes sense).
What should I store in my MySQL database? The token, secret and username? Or just the token?
What data type(s) would you use? How big are they?
Thanks!
They're not very big (maybe 15 or 20 chars, can't remember exactly), and are strings. Note: this could change. Nothing in the OAuth spec describes how to generate tokens and secrets, nor what they look like. I expect they'll always be strings, but I might want to make the column a little bigger than currently necessary for contingency.
If you store them in the database, you need some other way of authenticating the users so that you know whose tokens to pull out and use so they can't be used maliciously. If you already have that and it's working then that makes sense, otherwise you might want to rethink it.
Another way to do it is to store their tokens in a cookie, the drawbacks of that are that (if you don't encrypt them or use SSL) they are traveling over the net in the clear, and if they change computers, browsers, or delete their cookies you have to make them go through the whole OAuth process again.
For a website with no other auth, I would encrypt them and store them in a cookie. If you already make them log in, then associate both the token and secret with the login and store them in the database.
There are other ways, too. You could use a randomly generated ID like a GUID/UUID in a cookie to point to a record in a database with the tokens if you didn't want to use encryption. All in all, it depends on how you want your application to behave from the users' point of view.
Make sure you handle the case where the user de-authorizes your app too.
The application secret and token, is specific to your application and that can be stored in database or some config file.
User token you should store in to databse with varchar (100) (at max) along with his twitter ID. you can get the twitter ID while getting the other details from twitter OAuth.
For further guidance, following this link
http://www.9lessons.info/2010/02/connect-twitter-api-with-oauth-using.html

Can passwords for other sites be stored securely?

My university has a portal which students use to register for classes. If you want to get into a full class, you have to keep checking the portal, and sign up when the class has an opening.
I wrote a tool that can check for openings and register automatically, but it needs the students university username and password. These passwords are tied to email accounts, network shares, server logins, and most every other university service.
Is there any way to do this securely?
In security, the most important thing is the "threat model". What kind of attack do you fear?
somebody may steal the computer where this program runs on: put the computer in a locked room.
somebody may hack into the computer and read it from memory: use firewalls and other protection against remote attacks
other users may read the hard disk where the password is stored: only store the password in memory (which would require re-entering it every time you start the program)
the super user may read the password even if it is in memory: only run the program on a computer where you trust the superuser.
etc.
Unfortunately, this is not really possible -- at least not the way you want to do it -- unless the university provides a key-based authentication API. You could always ask them nicely, but they'll probably be too busy to help. If you give your users full disclosure and keep your server secure, it should be enough.
Actually, there is one way to do it through the web without storing passwords -- you could use a Java or Flash app. Unfortunately your users would need to leave the browser open while the app does its work, but this way you wouldn't need to store the information.
You could encrypt the password strings when you store them and then decrypt them when you need to try logging in. Simply generate a symmetric key and use that to encrypt and decrypt the passwords for storage and retrieval (respectively).
You can't store them entirely secure because you'd need to be able to encrypt and decrypt so one-way hash algorithms like MD5, SHA-1, SHA-2 wouldn't suffice. You could look into something like DES or Triple-DES encryption.
I do not think there is. As Martin pointed out one way encryption won't do it for you. Also this will create a maintenance nightmare for you - every time a user changes password you will have to update your data.
I think to make it really work you have to change the design: find a way to do the registration without the user password, i.e. talk to the owners of the app if they would give you an account through which you can do registration on behalf of somebody else

md5 for emails too?

I'm creating a MySQL database with registered users, and I'm thinking to use md5 not only for passwords but for e-mails too.
I think this choice can improve user security, but I'm not yet an expert with databases and I'm not sure if this is wise or not!
I hope this isn't a stupid question!
Do you not want to be able to get the email addresses back later on, such as to email them with news of an update? Hashing is a one-way process.
Using a hash for the email address would work in terms of the user entering their email address to get a new temporary password, in that you would have the address right there and then - but if you needed to email them later, you wouldn't have the information any more.
If you store the emails as MD5 digests, you can't email your users anymore...
MD5 is one sided - it cannot be revered. For passwords, this is desireable - no one can figure out the password.
For emails, not so much - you will not be able to send emails to your users, only confirm it is the same as previously entered.
You should not only MD5 your passwords, but add salt value and hash resulting password multiple times, then save salt and hashed string in database. That way it will be harder to guess original password - it's not about your security (cracker can bruteforce passwords same way, but it'll be a little slower, which is good), it's about users security. Many of users use same password in multiple sites. More info in http://www.codinghorror.com/blog/archives/000953.html
You can use a one way hash like MD5 or SHA-2 to sign a message to make it harder to forge or alter, but there's no practical way to convert the hash back into a message.