Defence in Depth: Separate database operations by access level


ClassicPress has inherited from WordPress a codebase entirely devoid of even the concept of “defence in depth”.

The purpose of this petition is two-fold:

  1. Gain wider acknowledgment and acceptance of the need for defence in depth,
  2. Agree on a concrete first step in the process of providing defence in depth.

Creating full defence in depth properly is going to be a long, slow process, but I believe there are very worthwhile quick wins available.

There are many facets of defence in depth; I shall confine this petition to authorisation [1].


Over the years there have been many bugs in WordPress that have allowed some variation on “an unauthorised user being allowed to access something they shouldn’t”. The most recent is the REST API bug in 4.7.0/1 which allowed an unauthenticated user to insert/update/delete any post. This proposal would have completely prevented the bug from becoming a security issue.

The Problem

The fundamental issue is that CP has a single database connection which, by default, can do anything; if the authorisation checks in the code fail for any reason there is no way to catch it before the damage is done.

The Solution

The only solution is some form of separation of concerns.

The ideal separation is to have multiple database connections, each with a different level of access; ideal from a security perspective, but impractical.

Instead, I propose the addition of a number of database roles to the existing user, with the default role having only read access.

Roles, in one form or another, are common to all databases (with the exception of sqlite). Their exact functionality differs, but generally MySQL is the least capable; whatever works for MySQL is almost guaranteed to be possible on any other database we might consider supporting.

Each role would have a different level of access, but how the roles are structured requires further discussion. For example, we could mirror the CP user roles - which is probably too coarse, or we could mirror the low-level user rights - which is probably too fine and definitely too hard to implement in the first version [2]. We need a compromise and that requires discussion.

Due to the rather “basic” nature of the existing database schema the effectiveness of this approach is slightly blunted; for example, having all the posts and CPTs in a single table makes it difficult to restrict access by type [2], and unpicking this is not something to be undertaken lightly. However, it would still have stopped the REST API bug from becoming a security issue, and would generally prevent SQL injection attacks.

Future Implications

It is vital that any future developments take the security implications of the database schema into account, rather than just simplicity or conformity. For example, the “object relationship” research plugin must use individual tables for relationships so that there is enough granularity for database roles to be effective.

Ultimately, as part of implementing PDO support (which I am very much in favour of and hope we agree to do), we should look at implementing table-per-post-type, amongst other things. However, given the potential for breakage I cannot see how we could attempt that before v3.

[1] Distinct from authentication.
[2] Needing to use row-level permissions almost always means the schema is wrong.

Read-only archive:

Author: invisnet

Vote count: 11

Status: open


  • cp-research-plugin


This is not feasible for ClassicPress at this time. It may be revisited in the future.

This topic was automatically closed after 3 days. New replies are no longer allowed.