I ethvert it-system, hvor vigtige forretningsopgaver finder sted, er det vigtigt at have et eksplicit sæt af politikker og praksis, og at sikre, at disse respekteres og følges.
Introduktion til revision
En informationsteknologi-systemrevision er undersøgelsen af en organisations politikker, processer, procedurer og praksis vedrørende it-infrastruktur i forhold til et bestemt sæt af mål. En it-revision kan være af to generiske typer:
- Kontroller mod et sæt standarder på en begrænset delmængde af data
- Tjekker hele systemet
En it-revision kan dække visse kritiske systemdele, såsom dem, der er relateret til finansielle data for at understøtte et specifikt sæt af regler (f.eks. SOX), eller hele sikkerhedsinfrastrukturen i forhold til regler, såsom den nye EU GDPR-forordning, der adresserer behovet til beskyttelse af privatlivets fred og sætter retningslinjerne for håndtering af persondata. SOX-eksemplet er af førstnævnte type beskrevet ovenfor, hvorimod GDPR er af sidstnævnte.
Revisionens livscyklus
Planlægning
omfanget af en revision er afhængig af revisionsmålet. Omfanget kan omfatte en særlig applikation identificeret af en specifik forretningsaktivitet, såsom en finansiel aktivitet, eller hele it-infrastrukturen, der dækker systemsikkerhed, datasikkerhed og så videre. Omfanget skal være korrekt identificeret på forhånd som et tidligt trin i den indledende planlægningsfase. Det er meningen, at organisationen skal give revisor al den nødvendige baggrundsinformation for at hjælpe med planlægningen af revisionen. Dette kan være de funktionelle/tekniske specifikationer, systemarkitekturdiagrammer eller andre nødvendige oplysninger.
Kontrolmål
På baggrund af omfanget danner revisor et sæt kontrolmål, som skal testes af revisionen. Disse kontrolmål implementeres via ledelsespraksis, der formodes at være på plads for at opnå kontrol i det omfang, som omfanget beskriver. Kontrolmålene er knyttet til testplaner, og de udgør tilsammen revisionsprogrammet. Baseret på revisionsprogrammet organisationen under revision allokerer ressourcer for at lette revisoren.
Resultater
Revisor forsøger at få bevis for, at alle kontrolmål er opfyldt. Hvis der for et eller andet kontrolmål ikke er et sådant bevis, forsøger revisor først at se, om der er en alternativ måde, som virksomheden håndterer det specifikke kontrolmål på, og i tilfælde af at en sådan måde eksisterer, markeres dette kontrolmål som kompenserende og revisor vurderer, at formålet er opfyldt. Hvis der imidlertid slet ikke er bevis for, at et mål er opfyldt, markeres dette som et fund . Hvert fund består af tilstand, kriterier, årsag, virkning og anbefaling. IT-chefen skal være i tæt kontakt med revisor for at blive informeret om alle potentielle fund og sørge for, at alle efterspurgte oplysninger deles mellem ledelsen og revisor for at sikre, at kontrolmålet er opfyldt (og dermed undgå at finde).
Evalueringsrapporten
Ved afslutningen af revisionsprocessen vil revisor skrive en vurderingsrapport som et resumé, der dækker alle vigtige dele af revisionen, inklusive eventuelle potentielle resultater efterfulgt af en erklæring om, hvorvidt målet er tilstrækkeligt behandlet, og anbefalinger til at eliminere virkningen af resultaterne.
Hvad er revisionslogning, og hvorfor skal du gøre det?
Revisor ønsker at have fuld adgang til ændringerne på software, data og sikkerhedssystemet. Han/hun ønsker ikke kun at kunne spore enhver ændring af forretningsdataene, men også spore ændringer i organisationsdiagrammet, sikkerhedspolitikken, definitionen af roller/grupper og ændringer i rolle/gruppemedlemskab. Den mest almindelige måde at udføre en revision på er via logning. Selvom det tidligere var muligt at bestå en it-revision uden logfiler, er det i dag den foretrukne (hvis ikke den eneste) måde.
Typisk består det gennemsnitlige it-system af mindst to lag:
- Database
- Applikation (muligvis oven på en applikationsserver)
Applikationen vedligeholder sine egne logfiler, der dækker brugeradgang og handlinger, og databasen og eventuelt applikationsserversystemerne vedligeholder deres egne logfiler. Ren, let anvendelig information i logfiler, som har reel forretningsværdi fra revisorperspektivet, kaldes et revisionsspor . Revisionsspor adskiller sig fra almindelige logfiler (nogle gange kaldet native logfiler) ved, at:
- Logfiler er undværlige
- Revisionsspor bør opbevares i længere perioder
- Logfiler tilføjer overhead til systemets ressourcer
- Logfilernes formål er at hjælpe systemadministratoren
- Revisionsspors formål er at hjælpe revisor
Vi opsummerer ovenstående i følgende tabel:
Logtype | App/System | Revisionsstivenlig |
---|---|---|
Applogfiler | App | Ja |
App-serverlogfiler | System | Nej |
Databaselogfiler | System | Nej |
Applogs kan nemt skræddersyes til at blive brugt som revisionsspor. System logger ikke så let, fordi:
- De er begrænset i deres format af systemsoftwaren
- De handler globalt på hele systemet
- De har ikke direkte viden om specifik forretningskontekst
- De kræver normalt yderligere software til senere offline-parsing/-behandling for at producere brugbare revisionsvenlige revisionsspor.
På den anden side placerer app-logfiler et ekstra softwarelag oven på de faktiske data, således:
- Gør revisionssystemet mere sårbart over for applikationsfejl/fejlkonfiguration
- At skabe et potentielt hul i logningsprocessen, hvis nogen forsøger at få adgang til data direkte på databasen uden om app-logningssystemet, såsom en privilegeret bruger eller en DBA
- Gør revisionssystemet mere komplekst og sværere at administrere og vedligeholde, hvis vi har mange applikationer eller mange softwareteams.
Så ideelt set ville vi være på udkig efter det bedste af de to:At have brugbare revisionsspor med den største dækning på hele systemet inklusive databaselag, og konfigureres ét sted, så selve logningen nemt kan revideres ved hjælp af andre ( system) logfiler.
Revisionslogning med PostgreSQL
De muligheder, vi har i PostgreSQL vedrørende revisionslogning, er følgende:
- Ved at bruge udtømmende logning ( log_statement =alle )
- Ved at skrive en tilpasset triggerløsning
- Ved at bruge standard PostgreSQL-værktøjer leveret af fællesskabet, såsom
- audit-trigger 91plus (https://github.com/2ndQuadrant/audit-trigger)
- pgaudit-udvidelse (https://github.com/pgaudit/pgaudit)
Udtømmende logning i det mindste for standardbrug i OLTP- eller OLAP-arbejdsbelastninger bør undgås, fordi:
- Producerer enorme filer, øger belastningen
- Har ikke indre kendskab til tabeller, der tilgås eller ændres, udskriver blot erklæringen, som kan være en DO-blok med en kryptisk sammenkædet erklæring
- Har brug for yderligere software/ressourcer til offline-parsing og -behandling (for at producere revisionssporene), som igen skal inkluderes i revisionens omfang for at blive betragtet som troværdig
I resten af denne artikel vil vi prøve de værktøjer, som fællesskabet leverer. Lad os antage, at vi har denne enkle tabel, som vi vil revidere:
myshop=# \d orders
Table "public.orders"
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+------------------------------------
id | integer | | not null | nextval('orders_id_seq'::regclass)
customerid | integer | | not null |
customer | text | | not null |
xtime | timestamp with time zone | | not null | now()
productid | integer | | not null |
product | text | | not null |
quantity | integer | | not null |
unit_price | double precision | | not null |
cur | character varying(20) | | not null | 'EUR'::character varying
Indexes:
"orders_pkey" PRIMARY KEY, btree (id)
audit-trigger 91plus
Dokumenterne om brug af triggeren kan findes her:https://wiki.postgresql.org/wiki/Audit_trigger_91plus. Først downloader og installerer vi den medfølgende DDL (funktioner, skema):
$ wget https://raw.githubusercontent.com/2ndQuadrant/audit-trigger/master/audit.sql
$ psql myshop
psql (10.3 (Debian 10.3-1.pgdg80+1))
Type "help" for help.
myshop=# \i audit.sql
Derefter definerer vi triggerne for vores bordordrer ved at bruge den grundlæggende brug:
myshop=# SELECT audit.audit_table('orders');
Dette vil skabe to triggere på tabelordrer:en insert_update_delere rækkeudløser og en trunkeringsudløser. Lad os nu se, hvad udløseren gør:
myshop=# insert into orders (customer,customerid,product,productid,unit_price,quantity) VALUES('magicbattler',1,'some fn skin 2',2,5,2);
INSERT 0 1
myshop=# update orders set quantity=3 where id=2;
UPDATE 1
myshop=# delete from orders where id=2;
DELETE 1
myshop=# select table_name, action, session_user_name, action_tstamp_clk, row_data, changed_fields from audit.logged_actions;
-[ RECORD 1 ]-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
table_name | orders
action | I
session_user_name | postgres
action_tstamp_clk | 2018-05-20 00:15:10.887268+03
row_data | "id"=>"2", "cur"=>"EUR", "xtime"=>"2018-05-20 00:15:10.883801+03", "product"=>"some fn skin 2", "customer"=>"magicbattler", "quantity"=>"2", "productid"=>"2", "customerid"=>"1", "unit_price"=>"5"
changed_fields |
-[ RECORD 2 ]-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
table_name | orders
action | U
session_user_name | postgres
action_tstamp_clk | 2018-05-20 00:16:12.829065+03
row_data | "id"=>"2", "cur"=>"EUR", "xtime"=>"2018-05-20 00:15:10.883801+03", "product"=>"some fn skin 2", "customer"=>"magicbattler", "quantity"=>"2", "productid"=>"2", "customerid"=>"1", "unit_price"=>"5"
changed_fields | "quantity"=>"3"
-[ RECORD 3 ]-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
table_name | orders
action | D
session_user_name | postgres
action_tstamp_clk | 2018-05-20 00:16:24.944117+03
row_data | "id"=>"2", "cur"=>"EUR", "xtime"=>"2018-05-20 00:15:10.883801+03", "product"=>"some fn skin 2", "customer"=>"magicbattler", "quantity"=>"3", "productid"=>"2", "customerid"=>"1", "unit_price"=>"5"
changed_fields |
Bemærk værdien for ændrede felter på opdateringen (RECORD 2). Der er mere avancerede anvendelser af revisionsudløseren, såsom at ekskludere kolonner eller bruge WHEN-sætningen som vist i dokumentet. Audittriggeren ser ud til at gøre arbejdet med at skabe nyttige revisionsspor inde i audit.logged_actions-tabellen. Der er dog nogle forbehold:
- Ingen SELECT'er (triggere udløses ikke på SELECT'er) eller DDL spores
- Ændringer af bordejere og superbrugere kan nemt ændres
- Bedste praksis skal følges med hensyn til appbrugere og ejere af appskemaer og tabeller
Pgaudit
Pgaudit er den nyeste tilføjelse til PostgreSQL for så vidt angår revision. Pgaudit skal installeres som en udvidelse, som vist på projektets github-side:https://github.com/pgaudit/pgaudit. Pgaudit logger i standard PostgreSQL log. Pgaudit fungerer ved at registrere sig selv ved modulindlæsning og give kroge til executorStart, executorCheckPerms, processUtility og object_access. Derfor understøtter pgaudit (i modsætning til trigger-baserede løsninger såsom revision-trigger diskuteret i de foregående afsnit) READs (SELECT, COPY). Generelt kan vi med pgaudit have to driftsformer eller bruge dem kombineret:
- SESSION revisionslogning
- Objekt revisionslogning
Sessionsauditlogning understøtter de fleste DML-, DDL-, privilegie- og diverse kommandoer via klasser:
- LÆS (vælg, kopier fra)
- SKRIV (indsæt, opdater, slet, afkort, kopier til)
- FUNCTION (funktionskald og DO-blokke)
- ROLE (tildel, tilbagekald, opret/ændre/slip rolle)
- DDL (alle DDL undtagen dem i ROLE)
- MISC (kassere, hente, checkpoint, vakuum)
Metaclass "alle" inkluderer alle klasser. - udelukker en klasse. Lad os f.eks. konfigurere sessionsrevisionslogning for alle undtagen MISC, med følgende GUC-parametre i postgresql.conf:
pgaudit.log_catalog = off
pgaudit.log = 'all, -misc'
pgaudit.log_relation = 'on'
pgaudit.log_parameter = 'on'
Ved at give følgende kommandoer (det samme som i triggereksemplet)
myshop=# insert into orders (customer,customerid,product,productid,unit_price,quantity) VALUES('magicbattler',1,'some fn skin 2',2,5,2);
INSERT 0 1
myshop=# update orders set quantity=3 where id=2;
UPDATE 1
myshop=# delete from orders where id=2;
DELETE 1
myshop=#
Vi får følgende poster i PostgreSQL-log:
% tail -f data/log/postgresql-22.log | grep AUDIT:
[local] [55035] 5b03e693.d6fb 2018-05-22 12:46:37.352 EEST psql [email protected] line:7 LOG: AUDIT: SESSION,5,1,WRITE,INSERT,TABLE,public.orders,"insert into orders (customer,customerid,product,productid,unit_price,quantity) VALUES('magicbattler',1,'some fn skin 2',2,5,2);",<none>
[local] [55035] 5b03e693.d6fb 2018-05-22 12:46:50.120 EEST psql [email protected] line:8 LOG: AUDIT: SESSION,6,1,WRITE,UPDATE,TABLE,public.orders,update orders set quantity=3 where id=2;,<none>
[local] [55035] 5b03e693.d6fb 2018-05-22 12:46:59.888 EEST psql [email protected] line:9 LOG: AUDIT: SESSION,7,1,WRITE,DELETE,TABLE,public.orders,delete from orders where id=2;,<none>
Bemærk, at teksten efter AUDIT:udgør et perfekt revisionsspor, næsten klar til at sendes til revisor i regneark-klar csv-format. Brug af sessionsrevisionslogning vil give os revisionslogposter for alle operationer, der tilhører klasserne defineret af parameteren pgaudit.log på alle tabeller. Der er dog tilfælde, hvor vi kun ønsker en lille delmængde af dataene, dvs. kun få tabeller, der skal revideres. I sådanne tilfælde foretrækker vi måske objektrevisionslogning, som giver os finkornede kriterier til udvalgte tabeller/kolonner via PostgreSQL's privilegiesystem. For at kunne begynde at bruge objektrevisionslogning skal vi først konfigurere parameteren pgaudit.role som definerer masterrollen som pgaudit vil bruge. Det giver mening ikke at give denne bruger nogen login-rettigheder.
CREATE ROLE auditor;
ALTER ROLE auditor WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT 0;
Vi angiver denne værdi for pgaudit.role i postgresql.conf:
pgaudit.log = none # no need for extensive SESSION logging
pgaudit.role = auditor
Pgaudit OBJECT-logning vil fungere ved at finde om brugeren auditor tildeles (direkte eller nedarvet) ret til at udføre den angivne handling udført på de relationer/kolonner, der anvendes i en erklæring. Så hvis vi skal ignorere alle tabeller, men har detaljeret logning til bordordrer, er dette måden at gøre det på:
grant ALL on orders to auditor ;
Ved ovenstående bevilling muliggør vi fuld SELECT, INSERT, UPDATE og DELETE logning på bordordrer. Lad os endnu en gang give INSERT, UPDATE, DELETE af de foregående eksempler og se postgresql-loggen:
% tail -f data/log/postgresql-22.log | grep AUDIT:
[local] [60683] 5b040125.ed0b 2018-05-22 14:41:41.989 EEST psql [email protected] line:7 LOG: AUDIT: OBJECT,2,1,WRITE,INSERT,TABLE,public.orders,"insert into orders (customer,customerid,product,productid,unit_price,quantity) VALUES('magicbattler',1,'some fn skin 2',2,5,2);",<none>
[local] [60683] 5b040125.ed0b 2018-05-22 14:41:52.269 EEST psql [email protected] line:8 LOG: AUDIT: OBJECT,3,1,WRITE,UPDATE,TABLE,public.orders,update orders set quantity=3 where id=2;,<none>
[local] [60683] 5b040125.ed0b 2018-05-22 14:42:03.148 EEST psql [email protected] line:9 LOG: AUDIT: OBJECT,4,1,WRITE,DELETE,TABLE,public.orders,delete from orders where id=2;,<none>
Vi observerer, at outputtet er identisk med SESSION-logningen diskuteret ovenfor med den forskel, at i stedet for SESSION som revisionstype (strengen ved siden af AUDIT:) får vi nu OBJECT.
En advarsel med OBJECT-logning er, at TRUNCATEs ikke logges. Vi er nødt til at ty til SESSION-logning for dette. Men i dette tilfælde ender vi med at få al WRITE-aktivitet for alle borde. Der er samtaler blandt de involverede hackere for at gøre hver kommando til en separat klasse.
En anden ting at huske på er, at i tilfælde af arv, hvis vi GIVER adgang til revisoren på en underordnet tabel, og ikke den overordnede, vil handlinger på den overordnede tabel, som oversættes til handlinger på rækker af den underordnede tabel, ikke blive logget.
Udover ovenstående skal de it-folk, der er ansvarlige for logfilernes integritet, dokumentere en stram og veldefineret procedure, som dækker udtrækningen af revisionssporet fra PostgreSQL-logfilerne. Disse logfiler kan blive streamet til en ekstern sikker syslog-server for at minimere risikoen for interferens eller manipulation.
Oversigt
Vi håber, at denne blog har hjulpet dig med bedre at forstå bedste praksis for revisionslogning i PostgreSQL, og hvorfor det er så vigtigt at oprette et revisionsspor for at forberede en it-revision. Et revisionsspor vil give et sæt rene, brugbare oplysninger, der vil hjælpe din revision til at forløbe problemfrit.
ClusterControl kan hjælpe med at automatisere og administrere de fleste databaserelaterede opgaver og samtidig sikre databasesikkerhed, tilgængelighed og ydeevne – uanset dit valgte system. Download en gratis prøveversion af ClusterControl i dag for at se, hvordan din virksomhed kan drage fordel af værktøjet og de operationer, det udfører. Hvis du ikke allerede har gjort det, så sørg for at følge os på Twitter og LinkedIn, og abonner på vores feed, så ses vi i den næste blog.