Toate articolele
Software reglementat · 5 min citire ·

Cum construiești un audit trail care rezistă la audit

Tiparele de model de date pentru un audit trail credibil — tabel-umbră, tabele temporale sau event sourcing — și compromisurile fiecăruia.

audit trailmodel de dateSQL Serverintegritatea datelor

Acest articol e perspectiva unui inginer care a lucrat sub aceste cerințe, nu consultanță de reglementare. Pentru decizii de conformitate, consultă specialistul vostru de calitate/reglementare.

Într-un articol anterior am descris ce cere reglementarea de la un audit trail. Aici e partea pe care o scrii efectiv: cum arată modelul de date.

Diferența dintre un audit trail care trece un audit și unul care pică nu e volumul de informație. E dacă poți răspunde convingător la o singură întrebare: „de unde știm că înregistrarea asta nu a fost modificată ulterior?“

Ce trebuie să captureze, de fapt?

Minimul util pentru fiecare intrare:

  • cine — identitatea utilizatorului, nu contul tehnic al aplicației;
  • când — marcaj de timp dintr-o sursă unică, cu fus orar explicit;
  • ce — entitatea și identificatorul ei;
  • ce s-a schimbat — valoarea veche și cea nouă, nu doar „a fost modificat“;
  • de ce, unde are sens — motivul schimbării, dacă procesul îl cere.

Punctul critic e „valoarea veche“. Un audit trail care spune doar „câmpul X a fost modificat la ora Y“ nu îți permite reconstituirea stării. Iar reconstituirea e exact ce ți se cere.

Care sunt cele trei tipare uzuale?

Tipar Cum funcționează Când merită
Tabel-umbră Un tabel _audit paralel, scris prin trigger sau în stratul de acces la date Cel mai simplu de adăugat; bun când doar câteva entități sunt reglementate
Tabele temporale Baza de date păstrează automat istoricul rândurilor (system-versioned) Cost mic, istoricul e ținut de motor — dar nu captează cine și de ce
Event sourcing Starea curentă e derivată dintr-un flux de evenimente imutabile Cel mai puternic; cost mare de arhitectură — rareori justificat doar pentru audit

Atenție la rândul din mijloc, pentru că e capcana: tabelele temporale rețin SysStartTime/SysEndTime și nimic despre autor. Ca să satisfaci cerința de „cine“ de mai sus, tot ai nevoie de o coloană de identitate scrisă pe fiecare cale de modificare — exact tiparul fragil despre care avertizez mai jos. În plus, cine are drept de ALTER poate opri versionarea, modifica istoricul și o poate reporni, deci „garantat de motor“ e prea tare spus fără permisiuni strânse.

În practică, pentru sisteme de business, tabelele temporale dau de obicei cel mai bun raport efort/beneficiu — cu condiția să adaugi atribuirea, iar tabelul-umbră rămâne varianta pragmatică atunci când doar o parte din model e reglementată. Event sourcing-ul se alege pentru motive de domeniu, nu ca să bifezi conformitatea.

Cum îl faci credibil, nu doar complet?

Un audit trail e credibil dacă e greu de falsificat și se vede că e greu de falsificat.

  • Scris de sistem, nu de aplicație. Trigger-ele la nivel de bază de date sunt mai greu de ocolit decât codul aplicației, unde un dezvoltator poate uita o cale. Nu sunt însă infailibile: TRUNCATE, încărcările în bloc și dezactivarea explicită a trigger-ului le ocolesc — iar sub reglementare trigger-ul e el însuși cod care trebuie verificat.
  • Fără UPDATE și DELETE. Contul cu care rulează aplicația nu trebuie să aibă drept de modificare pe tabelele de audit. Dacă le poate schimba, presupunerea implicită la audit e că s-ar fi putut.
  • Timp dintr-o singură sursă. Ora serverului de bază de date, nu a aplicației și cu atât mai puțin a clientului.
  • Identitate reală. Dacă totul e scris de contul app_user, audit trail-ul nu atribuie nimic. Identitatea utilizatorului trebuie transmisă până la nivelul unde se scrie.
  • Legat de înregistrarea concretă, prin cheia ei stabilă — nu prin text liber.

Opțional, dar valoros: înlănțuire prin hash (fiecare intrare conține hash-ul celei anterioare). Nu previne modificarea, dar o face detectabilă — cu condiția să ancorezi lanțul în afara bazei de date (o amprentă publicată periodic, stocare WORM). Fără ancoră, cine poate rescrie un rând poate recalcula tot lanțul, iar detectabilitatea e zero.

Ce despre datele personale?

Aici apare tensiunea reală: reglementarea cere păstrare, GDPR cere minimizare și, uneori, ștergere.

Ce funcționează în practică:

  • nu scrie în audit trail mai mult decât ai nevoie — referințe, nu copii complete ale datelor sensibile;
  • redactează secretele (parole, chei, token-uri) înainte de scriere, întotdeauna;
  • pentru date personale, ia în calcul pseudonimizarea — audit trail-ul păstrează un identificator, iar maparea către persoană trăiește separat, cu propriul control de acces.

Merită știut că GDPR prevede excepții de la ștergere atunci când prelucrarea e necesară pentru respectarea unei obligații legale (art. 17 alin. 3 lit. b) — exact cazul păstrării impuse de reglementare. Nu există un răspuns universal; e o decizie care se ia împreună cu partea juridică. Dar dacă ai scris de la început date sensibile brute în audit trail, opțiunile tale ulterioare sunt foarte limitate.

Ce te costă la performanță?

Un audit trail cam dublează volumul de scrieri, adesea mai mult — un tabel-umbră cu valori vechi și noi, plus indecșii lui, depășește ușor 2×. Ce ajută:

  • limitează perimetrul — nu auditezi tot, ci ce e reglementat;
  • nu audita coloane derivate sau câmpuri de tip „ultima accesare“;
  • partiționează sau arhivează după vechime, păstrând regăsibilitatea;
  • indexează pentru interogările reale — de obicei „istoricul entității X“ și „ce a făcut utilizatorul Y în intervalul Z“.

Ultima e subestimată: un audit trail din care nu poți extrage răspunsuri rapid e, practic, inutilizabil la inspecție.

Greșelile care se plătesc cel mai scump

  1. Audit trail adăugat după ce modelul e stabilit pe UPDATE-uri distructive — istoricul dinaintea schimbării nu mai există.
  2. Scriere din aplicație pe toate căile, mai puțin una. Exact aceea va fi găsită.
  3. Tabele de audit editabile de contul aplicației.
  4. Fără fus orar sau cu ore luate din surse diferite.
  5. Fără test. Audit trail-ul e funcționalitate; dacă nu e testat, se strică tăcut la primul refactor.

Dacă lucrezi la un sistem unde trebuie să poți dovedi istoria datelor și vrei o a doua opinie pe model, hai să vorbim.

Unde am lucrat sub aceste cerințe

  • Capgemini — client Waters Corporation

    Software Engineer (contract)

    iun. 2022 – mai 2023

  • Cerner Corporation

    Software Engineer

    oct. 2016 – oct. 2019

Proiectul din spatele articolului Workly — Pontaj & Operațiuni Interne Pontaj, concedii, documente, tickets, assets și stocuri — multi-tenant, configurabil per firmă.

Ai un proiect similar?

Dacă lucrezi la ceva din zona asta, hai să vorbim 30 de minute.

Programează o discuție
Toate articolele