Store 'sensitive' data in MySQL DB - php

How should 'sensitive' data be stored in MySQL Database?
1) Should I focus more on the security of the MySQL database and store the data as plain text?
I found a step by step tutorial on how to make a MySQL database more secure:
http://www.symantec.com/connect/articles/securing-mysql-step-step
2) Should I encrypt the data?
If yes, then how should the encryption be done?
Using MySQL aes_encrypt/aes_decrypt?
Using PHP AES functions/algorithm for encrypting/decrypting data?
How should the data be stored in MySQL?
BLOB
BINARY
VARBINARY
In my case the 'sensitive' data are payments done by individuals.
Thanks

It's a mixture of both. Two existing answers (at the time I wrote this https://stackoverflow.com/a/10718397/1015483 and https://stackoverflow.com/a/10718459/1015483) are valid - you need to look at about 5 methods of possible attack that I can think of
They get access to your DB server; so yes, secure that baby as much as is reasonable (Matt's answer)
Stand alone data hijacking (someone gets to your database data somehow else, could be a backup, could be they guess a password, could be MITM if you transfer data from one place to another). For this, you do encypt your data. You also may do a CSV dump for some reason and e-mail to someone. Whoops. But it happens. So encrypt (vlzvt's answer)
But three elements not mentioned:
They could gain access to your web server (if different from your DB server). If they have access to the webserver, all bets are off as they have your password, encyption keys the lot. So you need to make that even more secure than the DB server. (Matt might have meant that above - but just make it clear)
Similar to above, but not to be forgotten, is if someone gets access to phpMyAdmin or your management consule. Don't use plain text auth or config stored passwords for access.
Finally there's your application itself (and the hardest to lock down). You need to prevent against SQL injections that may reveal data. Encrypting the data would stop minimise problems if someone did gain access through an untrapped query - so for this, encryption is the solution.
For part 2 of your question:
Using MySQL encrypt/decrypt functions will stop someone who has access to the raw data, but not MITM or SQL injection or even CSV dumps taken for transport.
So, IMO (and it's only my opinion and the way I've done it) is to encrypt with PHP and sned the encrypted data over the wire, as that stops all methods of trapping the data, and a CSV dump will be "scrambled".
If you do that, you may as well use the varbinary / blob types as it stops you accidentally trying to read/edit in phpMyAdmin. Plus potentially saves a few bytes nominally (although this depends on indexes and other stuff - so that alone is not a winning argument).
And now the down side: searching and sorting. Anything you index or search on, if encrypted, will only match the entire, exact, case sensitive string padded to the correct length (normally a search will be case insensitive, and you can do part searches with LIKE). And if you want to ORDER BY then you need the original strings. So bear than in mind when designing the structure.
Hope that helps.

What's the worst possible scenario if an attacker gets access to the plain text data? Given that you have to decrypt data in order to make it useful and you therefore need the encryption key to be somewhere accessible too, any attacker who can get to the DB will likely be able to get to the key as well, unless this is for archiving rather than e.g. a live website. I'd focus on the DB server security, unless you're carting HDDs around full of data which might get lost, but it really depends on why you need to encrypt it.

if you need to secure the data in your possibly hacked database, you can encrypt it
with mcrypt
$key = "mykey";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key,$data,MCRYPT_MODE_ECB,$key);
after that you can select BLOB,TEXT,MEDIUMTEXT or anything, based on the ~expected data size.
* for VARBINARY/BINARY you might need to pack it first.

The encryption operation has additional cost.
You need evaluate if in your scenario, this additional cost will be a problem, per example, if your data grow to considerable size.
The first frontier to avoid data leaks is a strong data access policy with profiles of access an so on. This has the disadvantage that you will need to manage the mysql and configurate it.
If you want care about the managment of profiles, you can encrypt the data assuming the extra cost in CPU and (depend of encyption algorithm) a extra storage space.
The security of the a system is equals to the security of more weak component, don't focus your effort only in encryptation task, this only give you the sensation of security, if the data can be decrypted, the only thing that the intruder needs is time and bruteforce to break the encryption

Related

Security for storing Data with PHP/PDO

After researching some hours about the topic of securing stored data I am a little bit confused of what is the best way to go now.
I have a databank for my (SSL) website where I am the only one that has access to it (hackers not counted). The login data is stored in a configuration file outside of the document root. In the database I have stuff like names and adresses from my clients and I am now worried that I need to implement all the security measures put forward by cryptography experts like in this answer (How do you Encrypt and Decrypt a PHP String?) or as asked here (Storing sensitive data securely in a database).
Since neither in my PDO/SQL and PHP seminars nor in regular posts here on stackoverflow I see these encryption and authentication methods being used or more specifically e.g. the keys when explaining PDO and PHP commands like INSERT INTO ... etc. I am unsure if it is now necessary to deploy encryption and authentication measures on every entry in my databank (is it even possible to do this afterwards?). The safety measures I have been informed about in the tutorials and articles are to use PDO's prepared statements.
If encryption and authentication is what I have to do, which is probably the case: Would it not be the most convenient and fastest way to simply use password_verify() and password_hash() for every sensitive data entry like it is done for passwords?
EDIT password_verify() and password_hash() are hashing (not encryption) methods, meaning that the data is irretrievably mangled and can only be confirmed but not read.
There are different types of database encryption, and depending on what data you want to protect, and why, you will do different things.
1) Database level encryption / Transparent data encryption
This is where your RDBMS encrypts everything for you at a file level. This means if anyone has access to the hard drive, or back-up media, they should not be able to access the data. See here for how to do it with MySQL: https://dev.mysql.com/doc/refman/5.7/en/innodb-tablespace-encryption.html (note this is not a PCI compiant solution, you'll need MySQL Enterprise Edition or another Enterprise database, or further security measures for that).
Note this does not protect your data if your application is compromised.
2) Field level encryption
You can encrypt data to be stored in any field you like. Here's a good answer that deals with that: https://stackoverflow.com/a/10945097/
The drawback of field level encryption is that you can't then query across the data. In each case you'll need to pull the data into your application, and then decrypt it one field at a time.
Note this does not protect your data if your application is compromised.
Note also the difference between 'encryption' and 'hashing' (password_verify and password_hash are about hashing)...encryption lets you secure data, store it and retrieve it. Hashing by definition does not let you retrieve the data.
In all cases the most important thing is to secure your application. Encryption of the underlying data is very much a secondary concern.
Since your web server (presumably) will have to have access to the data, it's somewhat useless to encrypt it at rest when the web server can (will have to be able to) decrypt it. Why? Because the web server is often the weak link. If an attacker can get access to it, they can do anything it can do, including decrypting the data.
Encrypting data at rest is only useful to prevent backchannel leaks, like improperly handled backups (which you're doing, right, right?) which dump the data in plaintext to a file which then inadvertently gets lost somewhere. To prevent that you should use whatever at-rest encryption your database offers transparent to the client; i.e. it's not something you should burden the application logic with if it's not integral to your application, it's something the database should worry about.
password_hash is a hash, it doesn't encrypt data, it irretrievably mangles it so it's impossible to get the original back from it. It's great for storing credentials which you need to confirm but not read; it's useless for anything else.
The main security points are to isolate your database server "physically", i.e. to not grant any access to it from anything but the web server; be very restrictive and specific about that. That then means the weak spots are at those ingress points like your web server. Ensure your web server is locked down as much as possible, exposes as little attack surface as possible (no unnecessary open ports or running services) and that your application code running on it doesn't allow any exploits (yes, that's the hard part that takes knowledge and discipline).
You can further tighten it down by segregating access to the database with different accounts which have different permission levels; i.e. some accounts only have read access to certain tables while others have read/write access to other tables. If you can split up your web server(s) into separate roles which all only need specific limited access, this further enhances security by avoiding vulnerabilities in one part enabling exploits in another.

What is the best practice for using AES_ENCRYPT and how secure is it?

I have been asked to do some research on how form submission data can be encrypted and ensure that it is stored securely in a database. The form submission will contain personal details about employees and these must be kept secure.
I have come across AES_ENCRYPT() during my research and have managed to apply this function so that it stores the data successfully in the database.
Example SQL statement I used:
"INSERT INTO employee (firstname) VALUES (AES_ENCRYPT('$name', '$encryption_key'))"
However, I have very limited knowledge in this area and am not sure if this is sufficient enough protection to prevent the data being hacked. What level of security does this provide? Is there anything that I have missed or another technique I could use to improve my implementation?
Additionally, I have stored the encryption key in a separate PHP file but I do not know what the recommended way to store it is. Any advice on this would be much appreciated.
Sorry if this question is vague or quite broad. I am a complete beginner in this area. I am happy to provide more information if it is needed.
AES (Rijndael) crypto is pretty doggone secure. In practice, unless your data is tremendously valuable, you can consider it secure. Unless some actor with vast resources decides they want to crack your encryption, nobody will.
But it's symmetric. It uses the same key to encrypt and decrypt stuff. So, you can consider it to be as secure as your key.
Your key is insecure. If a cybercreep cracks the server running your php code, they immediately get access to your key. And that gives them access to your encrypted data. And they have a bright neon road sign saying "here's the data I think is sensitive."
Don't forget that security depends on the weak link. Generally it's considered smarter to use your money and time to secure your server, rather than use symmetric encryption on a few columns of a dbms. In other words, with respect, you're probably wasting your time doing this column based encryption.
If you absolutely must encrypt data at rest, you should consider using an asymmetric (public / private key) cryptosystem. Encrypt stuff using the public key, and keep the private key on an airgapped secure system in case you need to decrypt some data.
Your example (first name) isn't sensitive enough to be worth this trouble.

Good way to encrypt data in MySQL table?

I am working on a fleet management system in PHP. My location tracking is GPS (SMS based): I receive an SMS that contains coordinates (Lat,Lng).
What I want is to encrypt those coordinates. When it comes to database it should be encrypted and when my web application wants it it should convert (decrypt) to its original form. I want to protect the coordinates from illegal access.
Now, how and where should I do encryption and decryption of that data? I need your opinions - I searched a lot but didn't get success.
There may be no point in encrypting these coordinates - anyone who has access to your database e.g. a database administrator will probably also have access to the decryption key on the web server (assuming you are thinking of using symmetric encryption). Thus, you should work out what kind of threat you are trying to protect against, and then see if your approach would do that.
If you are worried about hackers, the same rules apply as a rogue employee: a hacker who can steal a copy of your database may well be able to steal files off the web server.
If your location data does not need to be decrypted often, or if someone must enter a password to see it, that might be more achievable. You can encrypt the coordinates with a public key, and then only decrypt them with a password-protected private key. An attacker who gets hold of the public key will not be able to use it to decrypt.
It's worth considering also whether this data is so valuable and private that it is worth encrypting at all: you could invest the money you would spend on this project on a third-party security audit of your code instead.
Finally, if this data is regarded as private for data protection reasons, consider fuzzing the data (i.e. introducing small levels of random inaccuracy) rather than encrypting it. This is only an option if you don't need exact coordinates of your vehicles. This is a data protection technique used anonymise data in health trials, where exact location data creates a privacy risk. Of course exact location data is useful for vehicle tracking in the event of theft, so you need to decide what your priorities are here.
Further reading: you might be interested in a book called Translucent Databases, which considers encryption, hashing and fuzzing in the context of building data-protected database systems. It's a very thought-provoking read.
The suggestion that I would give is to get a HSM (Hardware Security Module) - something like YubiHSM and install it on a single server. Build an API around it to encrypt and decrypt the data.
Then, there are no keys to steal. For an attacker to decrypt the data, they would need to steal that HSM. The data is useless without the physical chip (which can't be copied).
For full security they should be encrypted befor they are send via SMS. That way nobody could try to get the SMS and read the cords in it. Second to that you could check if the encrption is done right to ensure that the data you get via SMS are valide. All of this could be done with encryption keys. But those need to be know to the sender and the resiver.
It's possible to encrypt when the data is stored in the DB aswell. But with that all the way to the DB is unsecure and could be used for attacks.
My bigest consurne would be that either someone catches the SMS that's not suposed to read it or even wore that someone sends a corrupted SMS with false data or an injection.
You can use mcrypt_encrypt function before entering coordinates in DB and use mcrypt_decrypt to decrypt them after retrieving from DB.

Best practice for storing emails encrypted in a database when working with Zend

I'm using Zend Framework with a LAMP stack. The client has requested protection of sensitive data, email included. In this project, emails will be used in two ways: for sending automated messages and for sending newsletters.
Has anyone worked with this? What algorithms are fast, reliable and can be used with a variable encryption key? Where should I store the encryption key? What engine should the database table use?
Ok, these are my 2cent.
For data that needs to be both encrypted and decrypted on the fly, I would suggest symmetric key algorithms, and the first that comes to mind is Blowfish. It is both fast, and relatively safe.
As to the variable keys. Usually there is little to no merit in having a different key for each entry that needs to be both encrypted and decrypted. Thus, I'd recommend using a single key, that is set in config file somewhere.
If you do need to have a key for each of the users/records, I'd recommend not keeping them in the db. Save them to flat-files on the disk.
As to table engine, it should not matter which one you choose, as long as it's not memory based.
As to merit - I think there is merit, if the client specifically asks for it. Even if there is technically little reason to create this encryption, this will contribute to the clients feeling of safety. Sure, it could be a false one, but it does help keep the data a bit more safe, and lets the client sleep more soundly. Therefore, if the client asks for it, go for it!
If you really have to do this, the answer Janis Peisenieks gives is a good starting point.
As far as I know, there's no safe way of storing keys in PHP - this means that an attacker who gets a moderate level of control over your system can retrieve the key from a config file, and use that to decrypt the data.
An attacker who wanted to know the email addresses of your users would have several options to retrieve that data - as GordonM writes, if your system sends email to those users, that email is relatively easily to intercept, and whilst the body may be encrypted, to "to address" is not.
Just checking that you will be hashing (not encrypting) passwords (if your system uses these?)

Is it advisable to encrypt url parameters instead of having them be in plain text?

I've had another developer pose the possibility of combining and encrypting/obsfucating all the parameters to pages for php, as a security measure against manipulations via crafted urls and to prevent interior knowledge of the database (e.g. knowing the id in the database of a specific entry).
In other words, instead of single or multiple public query parameters like ids, there would be a single encrypted blob that would be decrypted server-side, and re-encrypted when links are crafted.
Are there problems with this approach? Are there substantial advantages that make it worthwhile? Is this approach used in the wild to good effect?
You should design your system to prevent unauthorized access. Obsfucating (useful encryption on data the client generates is not a possibility) is not a worthwhile defense.
For instead, instead of giving the user a database ID, given them a hash (with perhaps a session seed) of the ID. The 128bit+ search space of the hash and (for reasonable DB sizes) low probability of collisions would be a much better approach. You could also encrypt the ID on the server for values the client never needs to manipulate (with a seed) but make sure it has the same properties as the hash I mentioned—namely that the search space is very large compared to the possible value space.
If you want to prevent users from messing around with the GET arguments, i would recommend the following:
Add a hidden form to all of your pages. Clicking anywhere on the page, would fill-in some data into the form and submit it securely through POST / SSL. Along the submission details, pass the URL where you want to direct user to.
On the server side, collect arguments, put them into session either globally or under some sort of identifier which you append to the destination URL. Send redirect back. This way if user refreshes page, he's not nagged about POST data. Also if he starts messing with going back and sideways in the application, kill that session cache and send him to starting page.
I have seen this technique in some on-line banking softwares. Another benefit is that user can't open new window.
In my opinion it can add some degree of security, but would severely change development approach and give you more work. I never used this approach myself and I think that ID's are safe to pass around as long as you have a proper ORM system in place which under no circumstances won't let user A access data by user B regardless of what kind of code your developers will write.
There may be some cases when this type of URL encryption (or Obsfucating) is useful. Let's say you build a pretty robust security in your application and all your hosts are safe and sound.
Now if your operations staff happens to be external and you don't want them to know/see these sensitive data (IDs) by changing log levels on the fly then it is better to encrypt them and decrypt them on demand by individual module.
As a general practice one should not pass any sensitive data in URL parameters and care should also be taken to NOT to log them even at higher level.

Categories