5

I'm using the PHP mcrypt library to cryptograph and store (MySQL) data using AES.

I was wondering if there is a good way to do this without having a hardcoded encryption/decryption key in my code.

If a hacker gets access to my server he will be able to see the files and my key on the code, therefore accessing all the data on the database.

Thanks.

9
  • You would need a key somewhere. Better to store it in your code than in the database where the encrypted data lies. Commented Jul 12, 2016 at 3:56
  • Yeah, but I was wondering if there was a more secure way. Storing the password in the code kind of breaks the whole point. The only scenario where this would be effective is if the hacker only had access to the database, not the whole server. Commented Jul 12, 2016 at 4:00
  • 1
    Exactly. That's normally the point. If they get their hands on a database dump or access to the database server, they can't use that information. If they get access to the web server, it doesn't really matter because they'll be able to do anything including intercepting calls/data and reverse engineering Commented Jul 12, 2016 at 4:01
  • Generally, if the server is compromised, everything is compromised so symmetrically encrypting your db data at the server doesn't really help so don't do it. Commented Jul 12, 2016 at 4:02
  • 1
    Encrypting the data with AES is a normal practice for storing credit card info. You can't get around storing the key on the web server. Commented Jul 12, 2016 at 4:05

2 Answers 2

5

I'm using the PHP mcrypt library to cryptograph and store (MySQL) data using AES.

You may wish to reconsider your choice in cryptography library.

I was wondering if there is a good way to do this without having a hardcoded encryption/decryption key in my code.

Store it in a configuration file outside your document root? For example, defuse/php-encryption.

If a hacker gets access to my server he will be able to see the files and my key on the code, therefore accessing all the data on the database.

If a hacker gets access to your server, symmetric-key encryption cannot save you. Public-key encryption, however, can preserve confidentiality.

Using Halite, this is easy to solve:

  1. You can only encrypt on the server; never decrypt.
  2. Your secret key must be kept offline and used by a human.

Online Code (Assumes PHP 7.0 and Halite 2.1)

<?php
declare(strict_types=1);
use ParagonIE\Halite\{
    Asymmetric\Crypto as Asymmetric,
    KeyFactory
};

$publicKey = KeyFactory::loadEncryptionPublicKey("/path/to/public/key");
$encrypted = Asymmetric::seal("Whatever secret data we want", $publicKey);
// Now do whatever you need with $encrypted

Offline Code (Assumes PHP 7.0 and Halite 2.1)

<?php
declare(strict_types=1);
use ParagonIE\Halite\{
    Asymmetric\Crypto as Asymmetric,
    KeyFactory
};

$salt = ""; // Generate from random_bytes(16) once, then persist.
$password = ""; // Create a strong password

$keyPair = KeyFactory::deriveEncryptionKeyPair($password, $salt);
$secretKey = $keyPair->getSecretKey();
$publicKey = $keyPair->getPublicKey();

// To have the public key to a file to upload to the server:
   KeyFactory::save($publicKey, '/path/to/public/key');

$decrypted = Asymmetric::unseal($encrypted, $secretKey);
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, that was a great answer! I've decided to use a public key to encrypt the data. This way if I get hacked the hacker won't have access to the private key. Awesome!
I'm using PHP's openssl_public_encrypt. Is that a good idea?
Perhaps this is a separate question but is there any way to change the password once it's been set? Otherwise the only way I can see is decrypting everything then re-encrypting it again.
The example code derives the key from a password. Protecting a key with a password without deriving the key from the password is possible with Defuse's PHP Encryption library.
|
2

It depends to what lengths you're willing to go, and your environment.

It's definitely a bad idea to keep the decryption key in the database - if anyone gets a hold of the database, they'll have both the decryption key and the data. By storing it on the application server, you can be certain that the above won't happen. But what if someone gets access to the application server, and then to the database through the application server? Now they have both the key and the data again. But this much you've said already.

Since you didn't mention your environment, let's assume:

  • standard LAMP stack
  • PHP runs as Apache module
  • you have a deployment tool/script to deploy your application

You could have a simple Apache configuration file that:

  • sets an environment variable to the value of your encryption key
  • gets included from the main apache configuration
  • is stored encrypted on disk/repo/wherever your deployment tool has access to

Then during deployment:

  • your deployment tool, as a part of its deployment steps, attempts to decrypt the encrypted config file and asks the deployment user for the key
  • deployment user provides the key from a system/method entirely unconnected to the running production application (e.g. offline secure password storage, etc.)
  • deployment tool copies the file to the production system and decrypts it
  • deployment tool (re)starts Apache on production systems
  • Apache loads the decrypted configuration file, setting the environment variable
  • once Apache is running, deployment tool deletes/overwrites/shreds/etc. the decrypted configuration file containing the secure encryption key

After this, the current state of things will be:

  • Apache has loaded the configuration in memory and the decrypted key is available to PHP via the environment variable
  • the secure key is not stored anywhere on the production system, it's only available in memory
  • the only way you can reload/restart Apache is via your deployment tool (which is probably what you want anyway)

How you could still be vulnerable:

  • shredding the file is secure when you're writing directly to the magnetic hard drive on a supported filesystem; it might not be as secure in a VM or SSD environment
  • an attacker with the access to the application server could dump the memory used by Apache and try to figure out how to get at the decryption key that's somewhere there
  • few seconds during deployment, while Apache loads, the file is unencrypted on the server; if an attacker has an uninterrupted access and knows what to look for, they might get lucky and find that file

Still, it's a lot safer than storing the unencrypted key on the application server, and it requires a very involved and highly sophisticated attacker to exploit. So, as I said at the beginning, it depends what lengths you want to go to.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.