I flere af de projekter, vi har arbejdet med, har kunder bedt os om at logge flere brugerhandlinger i databasen. De ønsker at kende alle de handlinger, som brugerne udfører i applikationen, men at fange og registrere alle menneskelige interaktioner kan være udfordrende. Vi skulle logge alle ændringer af data udført via systemet. Denne artikel beskriver nogle af de faldgruber, vi stødte på, og de metoder, vi brugte til at overvinde dem.
Introduktion
Jeg arbejder som løsningsarkitekt i finansielle tjenesteydelser. Det er vigtigt at holde et register over den sidste bruger, der ændrede en række. I de enkleste tilfælde er det nok at registrere tidsstemplet for ændringen for at have sporbarhed af ændringer. Her er et simpelt eksempel på en tabel, som gemmer kundeaftaler, der inkluderer last_changed
kolonner for bruger og tidsstempel.
Men i nogle tilfælde er dette ikke nok. Vi skal ofte have fuld sporbarhed (inklusive før og efter "billeder" af dataene). I nogle tilfælde har vi også brug for revision (hvem, hvad, hvornår).
Desværre er mange af vores systemer ikke designet til at give sporbarhed og auditerbarhed. Vi var nødt til at reverse engineering disse forretningsdriftskrav ind i systemerne.
Sporbarhed
I nogle tilfælde har vi fundet sporbarhed let at opnå. Mens vi i andre har fundet det svært eller endda umuligt. Afhængigt af dit system kan løsningen være enkel. Din dataadgang kan muliggøre en simpel indsprøjtning af logning af før- og efterbilleder af dataene. Denne logning kan implementeres således, at resultaterne gemmes i en databasetabel i stedet for i en logfil. I nogle produkter opnåede vi dette på en ligetil måde gennem vedholdenheden lag. For eksempel var dette muligt med Dvaletilstand .
Her kan du se en post for hvert revisionsspor-element, plus der vil være før- og efterværdier for hver kolonne, der har ændret sig. Også i tilfælde af, at en række slettes, gemmer vi disse oplysninger med functioncode
angiver sletning. Vi har valgt at bruge varchar(1) til at gemme koden for funktionen (C, R, D), der specificerer typen af ændring, snarere end navnet eller beskrivelsen af den "operation" (Create, Update, Delete), der blev udført . instance_key
indeholder den primære nøgle for det element, der blev tilføjet, ændret eller slettet, for sporbarhed.
Alligevel kan det være, at dit dataadgangslag ikke giver dig den nødvendige funktionalitet. For andre produkter gjorde vores dataadgangslag det ikke. I disse tilfælde krævede sporbarhed komplekse ændringer. For eksempel kan du få brug for hentning og logning af eventuelle data før ændring. Som jeg skrev, er dette muligt, men det kan være kompliceret at sætte på plads. Udviklere skal oprette en hentning af hver række, før de ændrer en række. Det ville ikke være muligt for en opdatering at køre uden et valg.
Hvordan kan du arbejde omkring sporbarhed? En mulig løsning er at sikre, at du kender startsituationen for alle data, det vil sige startsituationen skabt af statiske data indlæst i systemet. Derefter skal du logge alle ændringer. Med andre ord, hvad er alle "efter"-billederne af dataene? På denne måde ville det være muligt at “rulle frem ” fra de indlæste statiske data. Alle opdateringer foretaget indtil det tidspunkt anvendes. Dette er en mindre ideel situation, men kan være acceptabel.
En simpel tabel kan bruges, hvis den eneste tilgængelige information er den nye værdi og ikke den tidligere værdi.
Revisionsevne
I nogle situationer skal vi sikre, at alle handlinger, der udføres i systemet, er fuldt reviderbare . Hvem loggede ind på hvilket tidspunkt? Hvilke handlinger foretog hver bruger i systemet, inklusive kun at se data? Dette er vigtigt, fordi det kan være væsentligt, hvis en bruger kiggede på en betaling.
For at opnå finkornet sporing kan være svært at se kun på databaseadgang. Vi skal ofte se på et højere niveau og undersøge de handlinger eller tjenester, der udføres. I nogle tilfælde var vi i stand til at spore hvert servicekald for at vide, hvad en bruger gjorde på hvilket tidspunkt. Med en webservice input/output controller var logningen af serviceanmodninger ret let.
Her er et eksempel på en simpel brugerrevisionslog, hvor vi registrerer den handling, som hver bruger udfører. Jeg diskuterer nogle spørgsmål om denne tilgang i næste afsnit "Bevis".
En kort tabelbeskrivelse er givet nedenfor:
user_audit
tabel indeholder data revisionsindtastninger, som er tidsstemplede. Den primære nøgle består af audit_entry_time
stempel plus user_id
og bank_id
plus navnet på action
udført. Felterne har betydninger, der svarer til deres navne. Revisionstabellen gemmer result
af handlingen plus den faktiske class
som udførte handlingen, dens input parameters
og eventuelle errors
.
Her er et andet eksempel på et revisionsspor, hvor vi optager før- og efterbilleder af data, som blev ændret i en bestemt tabel (sammen med den udførte handling, brugeroplysninger og tidsstempling).
audit_trail
tabel indeholder revisionsindtastninger af før og efter billeder af dataene. Den primære nøgle består af audit_gen_key
det er en nøgle, der genereres af applikationen. Felterne har betydninger, der svarer til deres navne. Navnet på databasetabellen, som denne revisionssporpost er registreret for, er gemt i modified_table
plus "before"-billedet er gemt i prev_value
og "efter"-billedet i new_value
. module
som udfører ændringen og funct_type
ændringer (Opret, Opdater, Slet) gemmes også. Til sidst, revisionsoplysningerne for user_id
(og tilsvarende bank_id
) plus tidsstemplet for ændringen (date_last_changed
).
Så rammer vi en udfordring. Når der logges både sporbarhedsoplysninger og revisionsoplysninger, sker logningen to gange. Fra et revisionssynspunkt er dette irriterende. Revisorer skal sikre, at oplysningerne er de samme mellem disse to logfiler.
Bevis
En anden udfordring var at sikre logning af alle brugerhandlinger . Dette kræves ofte af revisorer i finanssektoren.
Nu har vi en rigtig udfordring. Vores løsning var at sikre central sporbarhed og auditabilitetslogning. Centrale "grænseflader" sikrer, at alle implementeringer af denne grænseflade inkluderede logning. Det var ligetil at sikre, at alle relevante klasser implementerede grænsefladen.
Dette sikrer naturligvis ikke 100 % bevis for logning. Det er et stærkt sikkerhedstjek, at alle relevante klasser blev logget efter behov.
Konklusion
Reverse engineering af ny forretningsfunktionalitet i et eksisterende system er altid en udfordring. Dette kan være endnu mere tilfældet, når den implementerede funktionalitet går til kernen.