1

Background

We are building a new project and are currently at the database design. We stumbled upon a problem which we cannot solve, we believe we have some solutions to it but we are not sure. The problem seems a tad ungoogleable, probably because we don’t know enough keywords on this topic.

Problem

In our case we are building a rest-api where a user authenticates with a token to do CRUD-operations to the endpoints.

Thats alright, you need to provide a valid token to access or modify a resource. Standard stuff.

However, being authenticated does not prevent you from modifying rows that doesn’t belong to you.

Thus a user could possibly change other users data, since there is no logic that handles that. In the case a table is located far between each other, you cannot rely on foreign key or primary key constraints - unless see Solution 2.

Solution 1

Add a field to every table that is either just a value holder or an actual fk. That field references the primary key of the “owner” or user in our case.

Solution 2

Take the performance hit and actually traverse all the way back up to the "owner" of the object/row.

Solution 3

Implement a RLS (row level security) solution but that does not seem to be the usecase for RLS or at least feels a bit to advanced for our usecase.

Question

So the question is what is the most performant while still solving the security issue? are there other solutions to this?

Solution 2 example:

Tables

user
    id - pk
    … 

company 
    id - pk
    … 
    user_id - fk 

note
    id - pk
    … 
    user_id

Session

user_session
    user_id
    … 

Data user can change:

SELECT
    *
FROM
    note
WHERE
    user_id = :session.user_id

When user wants to update the data:

UPDATE note
SET text = “foobar”
WHERE user_id = :session.user_id AND id=payload.id

If there exists a row with user_id that corresponds to the requesting user, and if the supplied primary key of the note exists.

References

Niclas
  • 510
  • 6
  • 19

1 Answers1

0

First, you need to decide your tenant strategy ("multi-tenancy" is your keyword). You can put user's data in different clusters, databases, schemas, or rows

Tenant-per-database is my preferred solution

does not seem to be the usecase for RLS

This is absolutely a usecase for RLS

You'll want an "owner_id" column in each "secured" table. Ensure the current_user is that owner. Cascading foreign keys to update owner_id if it changes

You could use WITH CHECK OPTION views instead of RLS, but RLS is still simpler

Neil McGuigan
  • 46,580
  • 12
  • 123
  • 152