In my database I store information which is encrypted and decrypted on the fly via a PHP-class.
Per application I use a private key appended with a user key to make sure the decryption only succeeds when a user tries to decrypt its own data.
The user 'key' is stored in the database; but the private key (application level) is stored as txt-file in the FS. Off course 'above' the web-root.
Considerations:
- If the database gets hacked: they end up with one part of the key, and encrypted data
- If PHP-stops or is corrupt: they end up with a single page with only include('../private/private.php') in it.
- If NGINX fails: the connection is 'just' dropped.
The only scenario I can think of is the corruption of the system itself. But the server runs a firewall, is updated regularly, runs fail2ban and only the services needed are run. SSH logins only via key-access etc etc
I was wondering if this is the 'best' practice.
Or if there is a better way to do this kind of encryption with above specifications?
What would be the correct access-rights to the key-file?
At the moment the database and webserver are both on the same server facing the internet. Is it better to split them and create an internet facing server with only the webserver; and put the database server and key-file on a different server in a private network?
edit: the private key to encrypt the data is build up by two components:
$key = $app_key . $user_key
I was wondering if this is the 'best' practice. Or if there is a
better way to do this kind of encryption with above specifications?
What would be the correct access-rights to the key-file?
Hard to implement
To be perfectly secure you would need to generate a private-public key pair on an HSM (hardware security module) such as a smartcard or an HSM box. The generated private key is created inside the HSM and can never leave the HSM, it can only be used for decrypt / sign operations inside the HSM itself, however it can never be read off the HSM. In this case if someone hacks your server, or even get complete control over your server, they can never get hold of the private key stored inside HSM. Depending on number of decrypt / sign operations required on your server you would need a reasonably performing HSM to decrypt required data. Accomplishing this task in pure PHP is however a long way to go ( you could implement your own C++ extension or use inter-process communication with a process that is able interact with HSMs)
Easier to implement
It is important to harden your server and minimize the attack vector as much as you possibly can. This mainly includes assigning appropriate permissions to files and database. Have a look at this for some good security practices.
To add my few cents you can use:
APC for in memory storage of your private key in php (this will also give you a boost in performance in compare with constanlty reading a key from a file). You would need to implement some secure mechanism (such as you entering a passcode ) to decrypt /restore an encrypted key into the APC every time you restart the web server.
Something like ionCube for encrypting and protecting your PHP scripts
Control you deployment process using an application container such as docker
At the moment the database and webserver are both on the same server
facing the internet. Is it better to split them and create an internet
facing server with only the webserver; and put the database server and
key-file on a different server in a private network?
Yes, separating the webserver from database server is definitely a good practice.
You can load the key into APC or something similar. This would require human input during boot (or perhaps kicked off from a more secured server). This would mean the key is never stored in any file on the server.
It's not perfect, but it's better than the more typical approach of using a local file.
q.v., Where should I store an encryption key for php?
Look at the OWASP Cryptographic Storage Cheat Sheet and its recommendations. Rule 2.1.5.4: Protects key in a key vaults. Keys should not be stored on the application or web server.
Related
I have a web app that uses AES encryption, everything works well, but I hard code the key in the php file. Here is an example ... encrypt($msg, 'password'); ... It calls my function and sends the password as a second parameter. The glaring flaw is that if someone accesses my server and looks in the php code they can easily take the key and decrypt the database. Should I be calling the password from an alternate server from an alternate database? Anyone have any simple ideas to protect the key? btw. I am stuck using one key for all the encryption because of the nature of the application.
This is the same chicken and egg problem which crops up all over the place in IT.
I expect this will be closed as a duplicate of something else - but its quicker to answer than look for duplicates.
There are different ways to mitigate the risk but none fix the problem. Which solution is right for you depends on what your specific risks are - are your backups encrypted / secure? Do you want the application to recover automatically from reboots? Is your application running on a system which is able to prove its identity/integrity to another machine? Does it run as part of a cluster.....
There are only so many places you can store data:
on another machine (access depends on an authentication mechanism)
on the filesystem (secret will be visible to anyone with access to that filesystem or a backup of it)
in memory (secrets are lot at reboot, and there is limited scope for protecting them from someone with access to the machine).
Don't feel bad. HSMs go to extreme lengths to provide security for secrets where it is practical to do so - but will hand them out to any authorized client (and the authentication schemes are not the most reliable). The model for managing master keys used by most password managers is truly awful.
Another key point is that a lot of the solutions which provide a moderate amount of protection are far from simple. I am current playing with the idea of writing my own password manager where the master encryption key is also encrypted with a key composed of each users password and a secret stored in memory on the computer. But this has issues around how to inject the system key at boot time securely and dealing with password resets.
The Linux kernel now has a virtual HSM capability which allows you to restrict data stored in memory to specific processes, process groups or users - but its not portable across operating systems.
I am using PHP's openssl to encrypt sensitive user data on my website. I have an ssl certificate to provide further encryption. But how do I keep the key secure?
I have done some research and come up with these steps to follow-
1) Store it in another server. Away from the root folder.
2)Some row specific keys are kept in the database, but encrypted with a master key.
3) The master key isn't in the stored in the drive but rather kept on the ram.
4) Proper authentication of the key before usage.
But how do I ensure no one gets the master key?
I have 2 servers- A and B.
A contains the protected database, B has the master key. Now, A, when necessary will retrieve the key from B and store it in the ram, preferably as a variable.
How do I ensure no one gets the key at server B? Should I store it as a php file or some other format? If it's another format, how do I make sure only server A's decrypt.php can only read it and no one else can?
Thanks for the help!
Keeping an encryption key secure is a very difficult problem. Generally the best you can do is make sure it is not in the http path and make the server as secure as possible. That includes two factor authentication and careful control of the second factor.
The only way to really keep the key secret is to insure it is never available and that would require a HSM (Hardware Security Module), a separate hardware device that performs the encryption/decryption so the key is never available. Think $5,000+.
You can take a look at AWS KMS or if you want to store some secrets on local premises, have a look at this open source project - Hashicorp Vault - it is pretty nifty.
What are you trying to protect your data from?
If you are trying to protect it from a SQL injection attack, for instance, then having it encrypted "inside" the database may offer some help.
If you are trying to protect it from someone who is attempting to gain privileged access to your web infrastructure it is an entirely different issue.
For example, if your servers have not been hacked and the code residing on the server has not been compromised, then if the software is doing it's job you'd be in a situation such that the software will decrypt only the data that the authenticated user is allowed to decrypt.
Generally, if someone gets privileged access to your server/code it may not make much difference where the key is stored. As noted by Zaph, leaving the web server unaware of encryption particulars by having a less accessible box sitting between the web server and the database may allow a higher level of security.
I'm doing something similar and will be using an AWS VPC to isolate sensitive/admin capabilities away from the web server. KMS will be used to keep the key encryption key opaque. Various types of monitoring will be performed and in the event an issue is detected the KMS key can be disabled - preventing access to data until the issue is resolved.
So I am encrypting data, storing it in the database, and decrypting it, using mcrypt.
I am wondering if it's safe to store the key for encryption in a php file outside of the public_html directory?
The reason for storing it in a file is that it needs to be used for multiple encryptions, so that multiple users can decrypt some data, and I figured storing it in a file is more secure than in the database table, right next to the encrypted data.
What are ANY potential security risks? Is it at ALL possible for a hacker to gain access to this file and thus the key?
Storing it above the public_html is a good idea. Your file should have the correct permissions configured so that only the web server or users that require it can read it.
An option is to split the key up and store in different places, for example part of it in a file on the file system, and part in the database. The benefit of this is it's harder to get the full key for an attacker because they need to access both the file system and the database.
Also consider your server environment has an affect on security, for example shared hosting is less secure than a dedicated server.
No one can say that it's impossible for an attacker to access the key because that depends on your entire server setup and config. Server's are most often compromised through vulnerabilities in software such as web servers, so you should follow good security practices such as keeping your software up to date.
If your server (as in its OS) is compromised, it is "game over", no matter whether your key is stored in a file or the database. So yes, it is "at all possible for a hacker to gain access to this file and thus the key" - by breaking into your server's OS.
If apache or PHP are compromised, but not the OS, you end up in a chicken-and-egg problem: If you put your key somwhere, where apache/PHP can access it, it can be taken by whoever breaks into apache/PHP. If not, you can't use it in your webapp.
This leaves only a scenario, where your webapp is compromised, but not the surrounding infrastructure - in this case, a file might indeed be a good idea: Many break-ins (e.g. most of the SQL injection variant) gain access to the DB, but not to the file system.
For sensitive environments we sometimes chose a model, where encryption/decryption is handled via a pair of FIFOs, with the real crypto being done by an external process - this can do some heuristics and refuse decryption on suspicious patterns.
I understand the concepts of securely storing data for the most part, including storing the data on a separate server that only allows connections from the application, key-pairs for encryption, etc. However, I'm still not understanding how separating the server makes it that much more secure.
For instance, suppose I have a web server, which is hardened and secure, and it captures the data from user input for storage. The data is encrypted and submitted via a db query or web service to the db server. The db server only allows connections from the web server and stores the data in an encrypted form. Therefore, if someone access the db, the data is worthless.
But, if someone access the web server, they will have access to the db as well as the encryption algorithm and keys, no? That being the case, why even have the data on a different server, as the transfer of the data is just another potential point of attack?
Is there someway to hide the connection information and encryption algorithms on the web server so that if it is compromised, access to the db server is not gained? Obfuscation isn't enough, I wouldn't think. Any ideas are welcome.
Thanks
Brian
There's a certain amount of magical thinking and folklore in the way people design for security, and you're right: storing data on a different server on its own doesn't necessarily make things more secure unless you've done all sorts of other things too.
Managing keys is a huge part of this; doing this in the context of web applications is a subject apart, and I'm not aware of any robust solutions for PHP. You're quite right - if your web application needs to be able to decrypt something, it needs access to the keys, and if the web app is compromized, the attacker also has access to the key.
This is why I've tended to use public key cryptography, and treated the public facing webserver as "write only" - i.e. the web server encrypts using the public key, stores in the database, and can never decrypt it; only a separate process (not available on the public internet) can use the private key to decrypt it. This way, you can store credit card details in your database, and only the application which charges the card has the private key to decrypt it; this app runs on a secure environment, not accessible from the internet.
Secondly, there are multiple levels of compromise - for instance, an attacker might get read-only access to your server's file system. If that file system includes the database, they could get hold of the data file, restore it to a server they control, and use the decryption key to steal your private data. If the database runs on a separate server(inaccessible from the internet), this attack route becomes impossible.
The fact that one route of attack leaves you open doesn't mean you can't protect against other attacks.
In most of my setups, the web server is in a DMZ of the firewall, and the DB is behind the firewall. I would never want to put the DB server outside the firewall. That extra level of security makes it much harder for someone to get to the data without authorization.
BTW, no web server on the net should be considered "hardened and secure". If it's available to the public, it can be hacked. It's just a matter of how hard they want to try.
You're right in your assumption that if someone hacks the webserver to the point they can log in as an admin, they can read and write the database. But that doesn't mean you should further weaken your setup by putting the DB on the web server. You want more security, not less.
EDIT:
Always think in terms of layers in your security. Separate critical parts into separate layers. This does two things. It makes it where the perp has more problems to solve, and it give you more time for detection and response.
So, in your scenario, access to the web server is one layer, you could then call an encryption server for a second layer (behind the firewall, which is another layer), and the encryption server could be the only machine allowed interaction with the DB server, which is another layer.
Layers make it more secure. They also, though, add burden, slowing the response time. So keep your solution balanced for your real-world requirements.
The problem here is that the keys are on the publicly-facing server which could be compromised - even if the server itself is "hardened", there may be a vulnerability in your app which gives an attacker access to keys or data.
To improve the security of your arrangement you could move just the code that handles encrypted data (along with the keys) onto a secure machine that can be accessed only by the web server, and only through a very restricted API (i.e. bare minimum that is needed). Each operation is logged in order to spot unusual behaviour, which could be symptomatic of an attempt to extract the secret data.
From a security perspective, putting the database into a separate server doesn't really help. If authentication tokens get compromised, it is game over.
However, it does make sense to separate database AND data access layer (DAL) from business logic and presentation. That way, if the application server falls prey to unscrupulous hands, database access is restricted to specific DAL operations which can go a long way of putting data out of harms way if properly implemented.
Other than that, there isn't much of a security benefit in segregating data storage into a separate server.
I probably need to protect a LAMP based server against being stolen or hijacked by a third party.
My idea is to use hard encryption to encrypt all data records using a master key, which can't be recovered, if the server shuts down. Thus, the master key can't be stored in the file system.
I'd provide the master key using a secure channel if the server runs.
The server should be able to use it, as long as it continues to run. If the server fails, the key should not be recoverable.
What would be the best solution in this case (shared memory?).
Do you mean you are trying to protect a physical server against theft? If so, I suggest that beyond the operating system's built-in security, the primary mechanism for physical security is not code-based at all, but rather a good old fashioned lock and key. Wonky home-brewed encryption mechanisms are not the answer - security through obscurity is not security.
Please provide more details on the kind of application and what data needs to be protected.
A pretty common way is:
run a standard linux distribution
have a root password and/or restrict login to ssh only
ssh into it when they system is up
mount the encrypted drives (provide the keyfiles over ssh or something, but only temporarily - delete them afterwars - you can have a script for that that downloads from an external sftp server that you can activate/deactive for the process)
when the server stops (power down etc) the drives get dismounted and the data is safe
when the server runs there is no way of getting to the data
additional chassies intrusion can be set up but is not really necessary and can be worked around by by a trained technician that really wants to
edit:
it is theoretically possible - with perfect knowledge of all involved chips and extremly high sensitive equipment to physically hijack into live conductor paths and catch some data. (i once saw a demonstration on ata-33 PATA cables.
the server would have to be put on a mobile power supply and brought into a fully equipped lab for that.
but you can totally avoid that if you have a system level encryption layer. theres no equipment on earth that can do somthing then.