Lab 12: Database Encryption

Time: 45 minutes | Level: Advanced | DB: MySQL 8.0, PostgreSQL 15

Overview

Database encryption protects data at two points: at rest (files on disk — InnoDB tablespace encryption, pgcrypto) and in transit (network — TLS/SSL). This lab covers both, plus Transparent Data Encryption (TDE) concepts.


Step 1: MySQL InnoDB Tablespace Encryption — Setup

docker run -d --name mysql-lab \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  mysql:8.0 \
  --early-plugin-load=keyring_file.so \
  --keyring_file_data=/var/lib/mysql-keyring/keyring \
  --default_table_encryption=ON

for i in $(seq 1 30); do docker exec mysql-lab mysql -uroot -prootpass -e "SELECT 1" 2>/dev/null && break || sleep 2; done

# Check encryption capability
docker exec mysql-lab mysql -uroot -prootpass -e "
SHOW VARIABLES LIKE 'default_table_encryption';
SHOW VARIABLES LIKE 'keyring_file_data';
SELECT * FROM performance_schema.keyring_keys;
"

📸 Verified Output:

💡 MySQL uses a keyring plugin to manage encryption keys. The key encrypts a table-level encryption key (TEK), which encrypts the actual data. This is two-tier encryption.


Step 2: Create Encrypted vs Unencrypted Tables

📸 Verified Output:


Step 3: Verify Encryption at Rest (Binary Inspection)

📸 Verified Output:

💡 This proves tablespace encryption is working: SSNs are invisible in the raw file, but plaintext is visible in unencrypted tables.


Step 4: MySQL — Require Secure Transport (SSL/TLS)

📸 Verified Output:


Step 5: PostgreSQL pgcrypto — Application-Level Encryption

📸 Verified Output:


Step 6: pgcrypto — Decrypt and Hash Functions

📸 Verified Output:

💡 bcrypt (gen_salt('bf', 12)) is the recommended password hashing algorithm. Cost factor 12 means 2^12 = 4096 iterations — slow enough to deter brute force, fast enough for login.


Step 7: PostgreSQL SSL/TLS — Verify Encrypted Connections

📸 Verified Output:


Step 8: Capstone — TDE Concept and pgcrypto Key Rotation

📸 Verified Output:


Summary

Encryption Type
MySQL
PostgreSQL
Protects Against

At-rest (tablespace)

ENCRYPTION='Y' + keyring plugin

pgcrypto column encryption

Stolen disk/backup

At-rest (passwords)

caching_sha2_password (built-in)

crypt() + gen_salt('bf')

Password table breach

Symmetric encryption

N/A (app-level)

pgp_sym_encrypt/decrypt()

Column-level breach

In-transit

REQUIRE SSL on user

ssl=on, sslmode=require

Network sniffing

TDE

InnoDB tablespace encryption

N/A natively

OS-level data access

pgcrypto Function
Purpose

pgp_sym_encrypt(data, key)

Encrypt with symmetric key

pgp_sym_decrypt(data, key)

Decrypt with symmetric key

crypt(password, salt)

Hash password with bcrypt/MD5/etc

gen_salt('bf', N)

Generate bcrypt salt, N=cost factor

Key Takeaways

  • Tablespace encryption protects files on disk — useless if attacker has DB access

  • Column encryption (pgcrypto) protects individual values — even privileged DB users need the key

  • In-transit encryption (TLS) is mandatory — enable and enforce with REQUIRE SSL / sslmode=require

  • Bcrypt (gen_salt('bf', 12)) is the right password hashing algorithm — never use MD5 or SHA1

  • Key rotation requires re-encrypting all data — plan for it in your encryption strategy

Last updated