Skip to content
English
  • There are no suggestions because the search field is empty.

09.01 The Encryption Extra Overview

The Encryption Extra (also called the Encrypted Database Extra) protects sensitive SimpleRisk fields from database exfiltration by encrypting them at rest with AES-256-CBC plus HMAC-SHA256 authentication. A single per-install master key (stored in extras/encryption/includes/init.php) encrypts roughly 30 sensitive fields across risks, assets, frameworks, mitigations, audits, and custom data.

Requires: Encryption Extra

Encryption-at-rest for SimpleRisk's sensitive fields is added by the Encryption Extra at simplerisk/extras/encryption/. The Extra is also labeled "Encrypted Database Extra" in some surfaces; both names refer to the same Extra.

Why this matters

A database with sensitive content (risk descriptions naming specific systems, audit findings citing unmitigated vulnerabilities, control test results detailing security gaps) is a high-value exfiltration target. A backup file copied to a thumb drive, a SQL injection that dumps a table, a misconfigured database that's exposed to the internet, a forensic image taken during an incident: all produce a database file in someone else's hands. Without encryption-at-rest, that file is plaintext; with encryption-at-rest, it's an opaque blob.

The Encryption Extra applies AES-256-CBC encryption to the most sensitive fields in the SimpleRisk schema. Roughly 30 fields across the risk register, asset inventory, framework definitions, mitigation plans, audit logs, and custom data become ciphertext at rest. The application transparently encrypts on write and decrypts on read; users and the UI experience the data normally.

The honest scope to know up front: this protects against database exfiltration; it doesn't protect against active runtime attack. An attacker who gains code execution on the SimpleRisk server (via a vulnerability in the application, an OS-level compromise, a malicious admin) reads the master key from disk and decrypts data in memory just like the application does. Encryption-at-rest raises the bar against database-only attacks; it doesn't raise the bar against full-server compromise.

The other thing worth knowing: the master key is a single per-install secret stored on the file system. It's at simplerisk/extras/encryption/includes/init.php after activation. Lose this file and your encrypted data is unrecoverable — there's no recovery service, no SimpleRisk-side key escrow, no backdoor. Backup discipline for this file is non-negotiable; treat it like the most-important credential in your environment.

The third thing: activation is a planned operation, not a click-and-walk-away action. The encrypt-everything pass runs as a background job; other users keep using SimpleRisk against the live plaintext tables while the job builds encrypted copies in temp tables. At the keystone moment SimpleRisk atomically swaps every encrypted temp table into place via a single multi-table RENAME TABLE and flips the Extra-active flag in the same stage — from any user's perspective, the database goes from plaintext to ciphertext in an instant. The page that kicked off the activation shows a progress overlay and polls until the job finishes. If anything goes wrong mid-migration, SimpleRisk surfaces a failure modal with a Restore from backup button that rolls the database back to the pre-activation snapshot SimpleRisk took before the first encrypt stage. Deactivation works the same way in reverse.

How frameworks describe this

Encryption-at-rest is specifically called out by every major security framework as a control for protecting sensitive data:

  • NIST SP 800-53 SC-28 (Protection of Information at Rest) requires the system to protect the confidentiality and integrity of information at rest with appropriate cryptographic mechanisms. The Encryption Extra implements this for SimpleRisk's sensitive fields.
  • NIST CSF v2.0 under Protect.DS (Data Security) treats data-at-rest protection as a default expectation; lack of it is a gap that auditors flag.
  • ISO/IEC 27001 Annex A A.8.24 (Use of cryptography) covers the policy and implementation expectations; encryption-at-rest for sensitive data is the canonical implementation.
  • PCI DSS v4.0 Requirement 3.5 mandates encryption of stored cardholder data; while SimpleRisk doesn't store cardholder data directly, programs in PCI-relevant environments often extend the requirement to other sensitive data classes.
  • HIPAA Security Rule §164.312(a)(2)(iv) (Encryption and Decryption) identifies encryption as an addressable specification for ePHI; healthcare programs running SimpleRisk for HIPAA-related GRC typically activate encryption.

The takeaway: encryption-at-rest is an expected baseline for any program holding sensitive content, and the Encryption Extra is SimpleRisk's implementation.

How SimpleRisk implements this

Database prerequisites

The activation job takes per-table write locks while it encrypts each table, so the SimpleRisk database user needs the LOCK TABLES privilege on the SimpleRisk schema. Fresh installs grant it automatically; existing installs gain it during the Encryption Extra upgrade that introduced the queue-based flow. If your DBA runs a least-privilege grant policy and the upgrade didn't have enough privilege to self-grant, the activation page surfaces the exact GRANT statement to run before retrying. The same precondition applies to the deactivation flow.

The cryptographic primitives

  • Algorithm: AES-256-CBC (Advanced Encryption Standard, 256-bit key, Cipher Block Chaining mode).
  • Authentication: HMAC-SHA256. Each ciphertext is HMAC'd to detect tampering on read; modified ciphertext fails the HMAC check and produces an error rather than silent garbage.
  • Library: OpenSSL via PHP's openssl_* functions (with a fallback to the legacy mcrypt extension on older installs; mcrypt is deprecated in PHP 7.2+ and the OpenSSL path is the default).
  • Per-record IV: each ciphertext has its own random initialization vector, prepended to the stored ciphertext. Two identical plaintexts produce different ciphertexts because they use different IVs.

This is a defensible, contemporary cryptographic configuration. Nothing fancy; nothing weak.

The key model

A single 256-bit master key per install:

  • Generated at activation time: 32 bytes from OpenSSL's cryptographically secure random number generator.
  • Base64-encoded for storage.
  • Stored in simplerisk/extras/encryption/includes/init.php as a PHP define('ENCODED_KEY', '{base64-string}'); line.
  • Loaded into PHP at runtime when the encryption functions are called.

Implications:

  • One key encrypts all encrypted data. There's no per-user key, no per-record key, no key escrow.
  • The key file's filesystem permissions are the security boundary. Anyone with read access to the file has the key. The file should be readable by the web server's PHP process and nothing else.
  • The key isn't password-derived. User password changes don't affect the encryption; the key persists across user activity.

What gets encrypted

Roughly 30 fields across the SimpleRisk schema, including:

  • Risks: subject, notes, assessment, mitigation_percent, current_solution, security_recommendations, security_requirements.
  • Assets: name, ip, details, additional fields.
  • Frameworks: name, description.
  • Framework controls: short_name, long_name, description.
  • Mitigations: planning, current_solution, security_recommendations.
  • Audit logs: message field.
  • Comments: comment text.
  • Custom data: values stored via the Customization Extra (when the field's encryption flag is on).

The exact list depends on the install's version and active Extras. The encrypted_fields table tracks which fields are actually encrypted.

What does not get encrypted:

  • Foreign keys and lookup IDs (you can still see which user owns which risk, even without the key).
  • Numeric scoring fields (impact, likelihood, calculated_risk).
  • Configuration settings (the settings table).
  • User credentials (handled separately via bcrypt — see Local Authentication and Password Policies).

The selective encryption keeps performance reasonable while protecting the substantive content.

The activation backup

Before the first encrypt stage runs, the activation job dumps the database into SimpleRisk's own schema as a single snapshot. The dump is chunked, so a multi-gigabyte database stores without any operator intervention.

The snapshot is the source for the Restore from backup button on the activation-failure modal. If the activation finishes successfully and you don't want the snapshot taking space in your database, you can delete it later — the snapshot is retained through both directions of the lifecycle (a deactivation later re-uses the same singleton tables to capture the encrypted state, so you can roll back either operation).

The snapshot is plaintext — it contains every sensitive field as it existed before encryption ran. The same database-level controls that protect the rest of your SimpleRisk schema protect this table; if you're encrypting because the database itself isn't trusted, plan to delete the snapshot after you've verified activation succeeded.

Activation, deactivation, and runtime

  • Activation: snapshots the database, builds an encrypted copy of each encryptable table alongside the original, swaps them all into place in a single atomic operation, writes the master key file, and switches the Extra on at that keystone moment. Other users keep using SimpleRisk against the live plaintext tables until the atomic swap. The work runs as a queued background job; the page that kicked it off polls for status and surfaces failure with a Restore from backup option.
  • Runtime: encryption and decryption are transparent. Encrypted fields are decrypted as they're read and encrypted as they're written; nothing in the UI changes. A daily job checks for any column still encrypted under an older scheme and queues it for re-encryption. You can trigger that check on demand with POST /api/v2/encryption/algorithm-check/trigger.
  • Deactivation: accessed from admin/encryption.php (the Encrypted Database Extra tile on the Configure Hub navigates there when the Extra is active). Snapshots the encrypted state the same way, builds a decrypted copy of each encrypted table alongside the original, swaps them all into place in a single atomic operation, and switches the Extra off at that keystone moment. Other users keep reading from the live encrypted tables until the atomic swap. Same Restore from backup affordance on failure as activation.

For multi-server deployments (load-balanced SimpleRisk behind multiple web servers): the init.php master key file must be present on every server. Deploy it to each app server during initial setup; treat it as configuration, not as application code.

Common pitfalls

A handful of patterns recur with the Encryption Extra.

  • Activating without backing up the master key file. The file at simplerisk/extras/encryption/includes/init.php is the only copy of the key. Server failure, file system corruption, accidental deletion — without an off-server backup, the encrypted database is permanently inaccessible. Back up immediately after activation.

  • Treating encryption as protection against runtime attack. It isn't. Compromise of the SimpleRisk server gives the attacker the key. Encryption-at-rest is one defense layer; runtime defenses (web server hardening, application security, OS security) are separate.

  • Forgetting that the activation snapshot is plaintext. The pre-activation snapshot contains every sensitive field exactly as it was before encryption. The same controls that protect the rest of your SimpleRisk database protect it — but if the database itself is part of your threat model, clear the snapshot once you're satisfied activation succeeded.

  • Activating on a production install without testing the workflow on a non-production instance. The job runs in the background, and the rollback path is the Restore from backup button on the failure modal. None of that is trivia you want to discover for the first time during a production change window. Test in non-production first.

  • Deploying multi-server SimpleRisk without copying the key file to each node. The non-keyed nodes can't decrypt; users hitting those nodes see broken pages or errors. Confirm the key file is on every app server.

  • Storing the key file in source control. Don't. The file contains the master key; checking it into Git puts the key in everyone's checkout, every backup of every clone, every CI pipeline log. Manage the key file as a deployment-time secret.

  • Confusing the encryption-at-rest layer with TLS. TLS protects data in transit (network). The Encryption Extra protects data at rest (database). Both are needed; neither substitutes for the other.

  • Assuming all SimpleRisk data is encrypted after activation. Selective encryption (only ~30 fields) means most of the schema is plaintext. Reports that pull lookup IDs, status counts, etc., still work without the key. This is operationally useful (reports don't break when the key is wrong); it also means database access still leaks structural information.

  • Not coordinating activation with the program team. Activation is a planned change. Other users keep using SimpleRisk during the run, but writes that land between the per-table encrypt and the final atomic swap are not carried into the encrypted tables. Communicate the planned time so heavy-write activity (bulk imports, automated integrations) can pause for the window.

  • Treating the activation snapshot as the long-term backup strategy. It's a one-time rollback artifact for the activation operation, not a recurring backup. Standard backup procedures (see Database Backup and Restore) cover the ongoing backups; the activation snapshot is just the rollback option for the activation itself.

Related