Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encrypt mysql database

I'm trying to build a platform for users who will store confidential data about their clients. The context is quite simple: french laws prohibit me from having access to the data that my users will store (for example medical records of patients).

So when a user submits data which will be stored in the database, he should be the only one having access to that information. For example by encrypting it with his password. That way, if I log into mysql, I would only see encrypted nonsense and no readable data.

My philosophy, which might be wrong, is to learn by doing it. Hope you guys are ok with my approach.

Problem is: I have no idea where to start, how to do that... and actually not even what to search for on google. I even tried to find something suitable on codecanyon.net for example and couldn't fond any relevant scripts.

Thanks in advance :) !

PS: I will actually have the same problem with files (jpg, word, pdf, xls... that should be enough for the users). But that's another story.

like image 786
YannickHelmut Avatar asked Oct 07 '15 00:10

YannickHelmut


People also ask

Does MySQL have encryption?

MySQL supports encrypted connections between clients and the server using the TLS (Transport Layer Security) protocol. TLS is sometimes referred to as SSL (Secure Sockets Layer) but MySQL does not actually use the SSL protocol for encrypted connections because its encryption is weak (see Section 6.3.

How do I encrypt a table in MySQL?

To encrypt data in an InnoDB file-per-table tablespace, run ALTER TABLE tbl_name ENCRYPTION = 'Y' . To encrypt a general tablespace or the mysql tablespace, run ALTER TABLESPACE tablespace_name ENCRYPTION = 'Y' . Encryption support for general tablespaces was introduced in MySQL 8.0.

What encryption is used in MySQL?

MySQL Enterprise Transparent Data Encryption (TDE) protects your critical data by enabling data-at-rest encryption in the database. It protects the privacy of your information, prevents data breaches and helps meet regulatory requirements including: Payment Card Industry Data Security Standard (PCI DSS)


2 Answers

Although I'm not familiar with the French data protection laws, I do have some experience with the general EU legislation. Probably you have to encrypt personal data in your system such way, that the person cannot be identified. This means, that technical data, such as a system specific id in a table can stay unencrypted. This is the only reason I believe you can actually make this work. Sort of. You have to work with lawyers to determine what data can stay unencrypted to comply with the laws and still to be able to provide a valuable service to your clients.

However, I believe that you are missing an important point: if you cannot have access to certain data, then that data MUST NOT arrive to your organisation in a plain format. Period. If it does, then you already have access to it. So, php (or any kind of server based encryption) or mysql based encryption solutions are out of the picture.

The only solution I can think of is it to team up with a 3rd party PKI provider, who will provide your clients with certificates ( perhaps on chip cards), and the client side of your application encrypts the sensitive personal data items on the client BEFORE they are sent to your server and also decrypt these data items on the client. This also means that you will have to use some plugins on the client side if you want this system to be web based. Probably you will need some signed java app to manage the card reader and the certificate.

The setup has 2 drawbacks for your clients:

  1. It's not a single provider they deal with, since the PKI provider must be an independent third party. You must not manage the certificates.
  2. In case the stored data gets corrupted, the encrypted data will be lost. So, you will have to implement some crazy backup and restore solution.
like image 187
Shadow Avatar answered Sep 25 '22 08:09

Shadow


So assuming the problem is as follows:

  • You need to encrypt the data before you store it.
  • You shouldn't have the keys to decrypt it, only encrypt it.

There's actually a tool for this: It's called a sealing API, and it can be accomplished through OpenSSL or Libsodium.

Sealing/Unsealing Data in PHP with Libsodium

$store_me = \Sodium\crypto_box_seal(
    $plaintext,
    $recipient_public_key
);

$visible = \Sodium\crypto_box_seal_open(
    $store_me,
    $recipient_keypair
);

Sealing/Unsealing Data in PHP with OpenSSL

/**
 * A human-usable variant of openssl_seal()
 * 
 * @param string $plaintext Your message
 * @param string $publickey_string PEM-encoded RSA public key
 * @param boolean $encode Hex-encode the output?
 * 
 * @return string
 */
function easy_seal($plaintext, $publickey_string, $encode = false)
{
    $pubkey = openssl_get_publickey($publickey_string);
    if ($pubkey === false) {
        throw new Exception('Could not load public key');
    }
    $sealed = '';
    $ekeys = [];
    $result = openssl_seal($plaintext, $sealed, $ekeys, [$pubkey]);
    if ($result === false) {
        throw new Exception('openssl_seal failed!');
    }
    if ($encode) {
        return json_encode([
            bin2hex($sealed), 
            bin2hex($ekeys[0])
        ]);
    }
    return json_encode([$sealed, $ekeys[0]]);
}

/**
 * Inverse operation of easy_seal()
 * 
 * @param string $ciphertext (the output of easy_seal())
 * @param string $privatekey_string PEM-encoded RSA private key
 * @param boolean $encoded Do we need to decode from hex?
 * 
 * @return string
 */
function easy_unseal($ciphertext, $privatekey_string, $encoded = false)
{
    list($sealed, $ekey) = json_decode($ciphertext, true);
    if ($encoded) {
        $sealed = hex2bin($sealed);
        $ekey = hex2bin($ekey);
    }
    $open_data = '';
    $privkey = openssl_get_privatekey($privatekey_string);
    if ($privkey === false) {
        throw new Exception('Could not load public key');
    }

    $result = openssl_open($sealed, $open_data, $ekey, $privkey);
    if ($result === false) {
        throw new Exception('openssl_open failed!');
    }
    return $open_data;
}

Usage Example

$public_key = file_get_contents('/path/to/publickey.pem');
$plaintext = 'Something something dark side';
$store_me = easy_seal($plaintext, $public_key);

// Elsewhere: 
$secret_key = file_get_contents('/path/to/secretkey.pem');
$visible = easy_unseal($store_me, $secret_key);

Demo: https://3v4l.org/BNavp

like image 23
Scott Arciszewski Avatar answered Sep 28 '22 08:09

Scott Arciszewski