W PostgreSQL jest potężna, ale często niedoceniana funkcja -
Row Level Security (RLS).
Mówiąc krótko, to
ochrona danych na poziomie wierszy tabeli, czyli - system decyduje,
które dokładnie rekordy użytkownik może zobaczyć lub zmienić, jeszcze zanim zapytanie trafi do twojego kodu Rails.
Jak to działa
W normalnej sytuacji dostęp do danych kontrolowany jest w aplikacji - na przykład w Rails piszemy:
@posts = Post.where(user_id: current_user.id)
Jednak RLS pozwala delegować tę kontrolę
samej bazie.
Włączasz politykę bezpieczeństwa dla tabeli:
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY user_is_owner
ON posts
FOR SELECT USING (user_id = current_setting('app.current_user_id')::int);
Po tym nawet jeśli ktoś wykona SELECT * FROM posts,
PostgreSQL automatycznie wstawi warunek, aby użytkownik widział
tylko swoje wiersze.
Jak zintegrować RLS w Rails
W Rails można przed wykonaniem zapytania ustawić current_user.id w kontekście bazy:
ActiveRecord::Base.connection.execute("SET app.current_user_id = #{current_user.id}")
I wtedy wszystkie zapytania (Post.all, Post.find, nawet joins) będą zwracać tylko dozwolone dane - bez dodatkowych where w kodzie.
To jest wygodne dla systemów wielodostępnych, SaaS lub API, gdzie bezpieczeństwo nie powinno zależeć tylko od poziomu aplikacji.
Po co to w ogóle
-
Bezpieczeństwo na poziomie Bazy Danych - nawet jeśli ktoś omyłkowo zapomni o where(user_id: ...), dane nie wyciekną.
-
Prostota zapytań - można pisać Model.all, nie myśląc o filtrach.
-
Jednolity kontrola dostępu - zasady są przechowywane razem z danymi, a nie rozrzucone po kontrolerach i serwisach.
RLS nie zastępuje autoryzacji w aplikacji. Jest to dodatkowy poziom ochrony, który gwarantuje, że nawet na niskim poziomie nikt nie uzyska "zbędnych" danych. Row Level Security - to jak where(user_id: current_user.id), ale wbudowane w samą bazę danych.