Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 [Bug]: Storage user MUST have create permissions, even if using existing table #1571

Open
3 tasks done
bryanvaz opened this issue Feb 26, 2025 · 1 comment
Open
3 tasks done
Labels
☢️ Bug Something isn't working ✏️ Feature

Comments

@bryanvaz
Copy link

Bug Description

Driver: PostgreSQL
Category: Security
Severity: MEDIUM

Problem:
It is currently not possible to use the postgres storage driver without elevated user permissions that allow the user to arbitrarily create tables. This is even true if you already have a table that matches the desired schema. The behaviour is different than valkey, redis, and a number of other drivers where table/namespace create permissions are considered elevated permissions that a webserver should not posses for normal operations.

Always runs init query when initializing the storage:

for _, query := range initQuery {
if _, err := db.Exec(context.Background(), fmt.Sprintf(query, cfg.Table)); err != nil {
db.Close()
panic(err)
}
}

init query will fail if user does not have CREATE ON SCHEMA permission, even if table already exists:

initQuery = []string{
`CREATE TABLE IF NOT EXISTS %s (
k VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT '',
v BYTEA NOT NULL,
e BIGINT NOT NULL DEFAULT '0'
);`,
`CREATE INDEX IF NOT EXISTS e ON %s (e);`,
}

Root Cause:
The issue seems to mainly arise because of the way that the PostgreSQL query engine(QE) is built. The QE seems to preflight the query to ensure the user has the permissions to perform all of the actions in the query, even if a logic branch may never be taken (i.e. QE will verify user has CREATE permission even though query has the IF NOT EXISTS predicate and table already exists). This behaviour is expected and pretty good as it minimizes the need for the QE to do permission checks during row-locking/table-locking operations.

Potential Fixes:

Bare minimum fix:
Run two separate queries, (1) first check if table exists, (2) if table does not exists, then create table

Slightly better fix:
Add Config flag that disables all Create/Drop operations, and panics/raises error if table does not exist, schema does not match, or reset via DROP is set to true

Tangential fixes:
Reset function should TRUNCATE instead of DROP to accomplish the goal of:

// Reset clears any existing keys in existing Table
//
// Optional. Default is false
Reset bool

How to Reproduce

Steps to reproduce the behaviour:

  1. Create a user in postgres that has full table and usage permissions, but no create permissions:
CREATE DATABASE fiber_store;

CREATE ROLE fiber_users;

GRANT CONNECT ON DATABASE fiber_user TO fiber_users;
GRANT USAGE ON SCHEMA public TO fiber_users;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO fiber_users;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO fiber_users;
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO fiber_users;

CREATE USER fiber_users WITH PASSWORD 'password';

GRANT fiber_users TO fiber_user;
  1. Connect to database using the admin user in psql or SQL IDE
  2. Create the table expected by Storage
CREATE TABLE IF NOT EXISTS sessions (
	k  VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT '',
	v  BYTEA NOT NULL,
	e  BIGINT NOT NULL DEFAULT '0'
);
CREATE INDEX IF NOT EXISTS e ON sessions (e);
  1. Create a new barebones Go program
  2. Create a github.com/gofiber/storage/postgres/v3 storage connection using the newly created fiber_user
  3. go run program
  4. Program will panic with the following error:panic: ERROR: permission denied for schema public (SQLSTATE 42501)
  5. Change user to admin user (usually postgres)
  6. go run updated program
  7. Program will proceed normally.
  8. Check db schema, table will be unaltered

Expected Behavior

If table already exists, matches desired schema and Config{ Reset: false }, store should connect successfully and continue normally.

Storage package Version

v3.0.1

Code Snippet (optional)

See reproduction

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.
@bryanvaz bryanvaz added the ☢️ Bug Something isn't working label Feb 26, 2025
@bryanvaz
Copy link
Author

I'm happy to patch with a PR if the error makes sense, just let me know if there is a specific branch I should be basing on/merging into

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
☢️ Bug Something isn't working ✏️ Feature
Projects
None yet
Development

No branches or pull requests

1 participant