Genomförande av en rollbaserad Ätkomstmodell med hjÀlp av Row Level Security i PostgreSQL

Utveckling av Àmnet Studie om genomförande av Row Level Security i PostgreSQL och för ett utförligt svar till kommentar.

Den anvĂ€nda strategin innebĂ€r konceptet "AffĂ€rslogik i databasen", vilket beskrivits mer detaljerat hĂ€r — Studie om genomförande av affĂ€rslogik pĂ„ nivĂ„n av lagrade funktioner i PostgreSQL

Den teoretiska delen Ă€r utmĂ€rkt beskriven i dokumentationen Postgres Pro — Radernas skyddspolicyer. Nedan diskuteras en praktisk tillĂ€mpning av en specifik affĂ€rsuppgift — en rollbaserad Ă„tkomstmodell till data.

Genomförande av en rollbaserad Ätkomstmodell med hjÀlp av Row Level Security i PostgreSQL

Artikeln innehĂ„ller ingenting nytt, inga dolda betydelser eller hemliga insikter. Det Ă€r bara en skiss av praktisk tillĂ€mpning av en teoretisk idĂ©. Om nĂ„gon Ă€r intresserad — lĂ€s. Om inte — slösa inte din tid.

UppgiftsstÀllande

Det Àr nödvÀndigt att begrÀnsa Ätkomst till att visa/infoga/Àndra/ta bort dokument i enlighet med anvÀndarens roll i applikationen. Med roll avses en post i tabellen roles kopplad med en mÄnga-till-mÄnga-relation till tabellen users. Detaljer om genomförande av tabeller utelÀmnas pÄ grund av trivialitet. Specifika detaljer relaterade till ÀmnesomrÄdet har ocksÄ utelÀmnats.

Implementering

Vi skapar roller, scheman och tabeller

Skapande av databasobjekt

CREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store;
CREATE TABLE store.docs
(
  id integer ,         --dokumentets id
  man_id integer , --dokumentets manager id
  stat_id integer ,  --dokumentets status id
  ...
  is_del BOOLEAN DEFAULT FALSE 
);
ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id);
ALTER TABLE store.docs OWNER TO store ;

Vi skapar funktioner för att genomföra RLS

Kontroll av möjligheten att utföra SELECT pÄ en rad

check_select

SKAPA ELLER ERSÄTT FUNKTION store.check_select ( current_id store.docs.id%TYPE ) RETURNERAR boolean AS $$
DECLARERA
  resultat boolean ;
  curr_pid integer ;
  curr_stat_id integer ;
  doc_man_id integer ;
BÖRJA 
  -- DBA har Ätkomst till alla dokument
  IF SESSION_USER = 'curr_dba'
  DÅ
    RETURERA TRUE ;
  SLUTA ;
  --------------------------------

  --Om dokumentet har etiketten 'borttaget' - visa inte i urvalet
  VÄLJ
    is_del
  IN
    resultat
  FRÅN
    store.docs
  WHERE
    id = current_id ;
 IF resultat = TRUE
 THEN
   RETURERA FALSE ;
 SLUTA ;
 --------------------------------

 --HÀmta id för nuvarande anvÀndare
 VÄLJ
   service_function.get_curr_pid ()
 IN
   curr_pid ;
 --------------------------------

 --HÀmta id för dokumentets ansvarige
 VÄLJ
   man_id
 IN
   doc_man_id
 FRÅN
   store.docs
 WHERE
   id = current_id ;
 --------------------------------

 --Om dokumentets ansvarige inte Àr nuvarande anvÀndare eller ansvarig inte Àr angiven
 --lÀgg till dokumentet i urvalet
 IF doc_man_id != curr_pid OR doc_man_id ÄR NULL
 THEN
   RETURERA TRUE  ;
 ANNARS
   --HĂ€mta dokumentets nuvarande status
   VÄLJ
     stat_id                                         
   IN
     curr_statid
   FRÅN
     store.docs
   WHERE
     id = current_id ;
    
   --Om status tillÄter att dokumetet visas - lÀgg till dokumentet i urvalet                     
   IF curr_statid = 4 ELLER curr_statid = 9
   DÅ
     RETURERA TRUE ;
   ANNARS
   --Annars - uteslut dokumentet frÄn urvalet
     RETURERA FALSE ;
    SLUTA ;
  SLUTA ;
  --------------------------------

 RETURERA FALSE ;
SLUTA
$$ SPRÅK plpgsql SECURITY DEFINER;
ALTERERA FUNKTION store.check_select( store.docs.id%TYPE  ) ÄGARE TILL store ;
ÅTERKALLA UTFÖRANDE PÅ FUNKTION store.check_select( store.docs.id%TYPE  ) FRÅN public; 
BEVAKA UTFÖRANDE PÅ FUNKTION store.check_select( store.docs.id%TYPE  ) TILL service_functions; 

Kontrollera möjligheten att utföra INSERT av en rad

check_insert

SKAPA ELLER ERSÄTT FUNKTION store.check_insert ( current_id store.docs.id%TYPE ) RETURNERAR boolean AS $$
DECLARERA
  curr_role_id integer ;
BÖRJA
  --DBA kan alltid lÀgga till en rad
  IF SESSION_USER = 'curr_dba'
  DÅ
    RETURERA TRUE ;
  SLUTA ;
  --------------------------------

 --HÀmta id för nuvarande anvÀndarroll 
 VÄLJ
   service_functions.current_rid()
  IN
    curr_role_id ;
 --------------------------------

--Om rollen tillÄter att skapa ett nytt dokument
--tillÄt
IF curr_role_id = 3 ELLER curr_role_id = 5     
DÅ
  RETURERA TRUE ;
SLUTA ;
--------------------------------
RETURERA FALSE  ;
SLUTA
$$ SPRÅK plpgsql SECURITY DEFINER;
ALTERERA FUNKTION store.check_insert( store.docs.id%TYPE  ) ÄGARE TILL store ;
ÅTERKALLA UTFÖRANDE PÅ FUNKTION store.check_insert( store.docs.id%TYPE  ) FRÅN public;
BEVAKA UTFÖRANDE PÅ FUNKTION store.check_insert( store.docs.id%TYPE  ) TILL service_functions; 

Kontrollera möjligheten att utföra DELETE av en rad

check_delete

SKAPA ELLER ERSÄTT FUNKTION store.check_delete ( current_id store.docs.id%TYPE )
RETURNERAR boolean AS $$
BÖRJA  
  --Endast DBA kan ta bort en rad 
  IF SESSION_USER = 'curr_dba'
  DÅ
    RETURERA TRUE ;
  SLUTA ;
  --------------------------------

  RETURERA FALSE ;
SLUTA
$$ SPRÅK plpgsql
SECURITY DEFINER;
ALTERERA FUNKTION store.check_delete( store.docs.id%TYPE  ) ÄGARE TILL store ;
ÅTERKALLA UTFÖRANDE PÅ FUNKTION store.check_delete( store.docs.id%TYPE  ) FRÅN public;

Kontrollera möjligheten att utföra UPDATE av en rad.

uppdatera_anvÀnder

SKAPA ELLER ERSÄTT FUNKTION store.update_using ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean SOM $$
BÖRJA  
   --Dokumenten med status 'borttagen' - kan inte redigeras
   OM is_del 
   DÅ
     RETURN FALSE ;
 ANNARS
    RETURN TRUE ;
  SLUT OM ;

SLUT
$$ SPRÅK plpgsql SÄKERHETSFÖRDELARE;
ALTER FUNKTION store.update_using( store.docs.id%TYPE , boolean ) ÄGARE TILL store ;
ÅTERKALLA KÖRNING PÅ FUNKTION store.update_using( store.docs.id%TYPE , boolean ) FRÅN offentlig;
GE KÖRNING PÅ FUNKTION store.update_using( store.docs.id%TYPE ) TILL service_functions;

uppdatera_kontroll

SKAPA ELLER ERSÄTT FUNKTION store.update_with_check ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean SOM $$
DEKLARERA
  current_rid heltal ;
  current_statid heltal ;
BÖRJA                

  --DBA kan visa raden
  OM SESSION_USER = 'curr_dba'
  DÅ
    RETURN TRUE ;
  SLUT OM ;
  --------------------------------

 --HÀmta id för rollen för den aktuella anvÀndaren
 VÄLJ
   service_functions.current_rid()
  IN
    curr_role_id ;
 --------------------------------                            

 --Borttagning av dokument - Àndra indikeringsflagga
 OM is_deleted
 DÅ
   --Om anvÀndarrollen ***
   OM current_role_id = 3        
   DÅ
      VÄLJ
        stat_id                                          
      IN
        curr_statid
      FRÅN
        store.docs
      VARFÖR
        id = current_id ;

      --Dokument i status *** kan inte tas bort
      OM current_status_id = 11
      DÅ
         RETURN FALSE ;
      ANNARS
      --Kan ta bort dokument i andra statusar
        RETURN TRUE ;
      SLUT OM ;

    --Annars, om anvÀndarrollen ***
    ELSIF current_role_id = 5            
    DÅ
      --Alla dokumentstatusar
      RETURN TRUE ;
    ANNARS
      --Andra anvÀndare kan inte ta bort dokument
      RETURN FALSE ;
    SLUT OM ;
 ANNARS      
   --Uppdatering av dokumentet Àr tillÄten
    RETURN TRUE ;
SLUT OM ;

RETURN FALSE ;
SLUT
$$ SPRÅK plpgsql SÄKERHETSFÖRDELARE;
ALTER FUNKTION store.update_with_check( store.docs.id%TYPE , boolean ) ÄGARE TILL store ;
ÅTERKALLA KÖRNING PÅ FUNKTION store.update_with_check( store.docs.id%TYPE , boolean ) FRÅN offentlig;
GE KÖRNING PÅ FUNKTION store.update_with_check( store.docs.id%TYPE ) TILL service_functions;

Aktivera politiken för radnivÄsÀkerhet för tabellen.

AKTIVERA RADNIVÅSÄKERHET

ALTER TABELL store.docs AKTIVERA RADNIVÅSÄKERHET ;

SKAPA POLICY doc_select PÅ store.docs FÖR SELECT TILL service_functions ANVÄND ( (VÄLJ store.check_select(id)) );
SKAPA POLICY doc_insert PÅ store.docs FÖR INSERT TILL service_functions MED KONTROLL ( (VÄLJ store.check_insert(id)) );
SKAPA POLICY docs_delete PÅ store.docs FÖR DELETE TILL service_functions ANVÄND ( (VÄLJ store.check_delete(id)) );

SKAPA POLICY doc_update_using PÅ store.docs FÖR UPDATE TILL service_functions ANVÄND ( (VÄLJ store.update_using(id , is_del )) );
SKAPA POLICY doc_update_check PÅ store.docs FÖR UPDATE TILL service_functions MED KONTROLL ( (VÄLJ store.update_with_check(id , is_del )) );

Resultat

Det fungerar.

Den föreslagna strategin möjliggjorde överföringen av implementeringen av rollmodellen frÄn affÀrsfunktionsnivÄn till datalagringsnivÄn.

Funktioner kan anvÀndas som mall för att implementera mer avancerade modeller för dataskydd, om affÀrskraven krÀver det.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster