Confidențialitate prin design în PA: o obligație de reglementare și o alegere arhitecturală

Regulamentul general privind protecția datelor (GDPR), care a intrat în vigoare la 25 mai 2018, nu se limitează la impunerea de obligații birocratică pentru administrațiile publice: articolul 25 stabilește că protecția datelor trebuie integrată chiar din faza de proiectare a sistemelor și proceselor informaționale care prelucrează date cu caracter personal. Acest principiu, cunoscut ca Confidențialitate prin design, transformă conformitatea cu reglementările într-una singură calitate arhitecturală a software-ului.

Pentru un dezvoltator sau arhitect care lucrează la sisteme PA italiene - registru digital, fișă electronică de sănătate, portaluri de acces la servicii cu SPID sau CIE, sisteme de management al procedurilor administrative - înțelegeți și implementați corect GDPR-by-Design nu este opțional. Sancțiunile prevăzute de Autoritatea Garanta pentru Protecția Datelor cu Caracter Personal pot atinge 4% din cifra de afaceri anuală globală pentru entitățile private; pentru AP, implicațiile includ blocaje către tratament, despăgubiri pentru daune și prejudicii semnificative reputației.

Ce veți învăța în acest articol

  • Cele 7 principii fundamentale ale confidențialității prin design și cum să le mapați pe decizii arhitecturale concrete
  • Modele de pseudonimizare și anonimizare pentru baze de date și API-uri guvernamentale
  • Implementarea modelului de minimizare a datelor în microservicii PA
  • Managementul consimțământului: arhitectura și implementarea unui sistem conform GDPR
  • Reținerea automată a datelor și dreptul la ștergere în bazele de date relaționale
  • Înregistrare de audit conformă: cum să urmăriți tratamentele fără a încălca confidențialitatea
  • DPIA (Data Protection Impact Assessment) pentru sisteme cu risc ridicat

Cele 7 principii fundamentale și impactul lor asupra arhitecturii

Ann Cavoukian, fost comisar pentru informații și confidențialitate din Ontario, a oficializat cele 7 principii ale confidențialității prin proiectare, care GDPR a fost implementat. Fiecare principiu se traduce în alegeri arhitecturale specifice:

Principiul PbD Articolul GDPR Model arhitectural Tehnici concrete
Proactiv, nu reactiv Articolul 25 Confidențialitatea modelării amenințărilor Evaluarea riscului de confidențialitate în faza de proiectare
Confidențialitate implicită articolul 25 alineatul (2) Înscrieți-vă în mod implicit Consimțământ explicit, minimizare în mod implicit
Integrat în design Articolul 25 alineatul (1) Arhitectură încorporată în confidențialitate Pseudonimizare, criptare în repaus
Funcționalitate completă Articolul 5 Evitare cu sumă zero Confidențialitate + securitate nu sunt în conflict
Securitate de la capăt la capăt Articolul 32 Apărare în profunzime TLS, criptare, managementul cheilor
Vizibilitate și transparență Articolul 13/14 Pista de audit + dezvăluire Înregistrare anonimizată, notificare de confidențialitate
Respect pentru intimitatea utilizatorului Articolul 7/8/17 Controale centrate pe utilizator Interfața de utilizare a consimțământului, dreptul de a fi uitat, portabilitate

Model 1: Minimizarea datelor în microservicii PA

Principiul minimizării (Art. 5(1)(c) GDPR) cere ca datele colectate să fie „adecvate, relevante și limitate la ceea ce necesare în raport cu scopurile pentru care sunt prelucrate”. Într-o arhitectură de microservicii, acest lucru se traduce în model Minimizarea datelor la limită: fiecare serviciu trebuie să primească doar datele de care are nevoie pentru a le efectua funcția sa specifică.

Luați în considerare un serviciu de verificare a identității pentru a accesa un beneficiu de asistență medicală. Serviciul nu are nevoie de nume informații complete ale cetățeanului pentru a verifica dacă are dreptul la prestație: un identificator anonim este suficient pentru el și pentru statut îndreptățit. Modelul este implementat prin DTO selective (Obiecte de transfer de date). e interogări de proiecție.

# Pattern Data Minimization - Esempio Python/FastAPI
# Scenario: servizio prestazioni sanitarie PA

from pydantic import BaseModel
from typing import Optional
import hashlib

# SBAGLIATO: trasferisce dati non necessari
class CitizenFullDTO(BaseModel):
    citizen_id: str
    fiscal_code: str
    first_name: str      # Non necessario per verifica
    last_name: str       # Non necessario per verifica
    birth_date: str      # Non necessario per verifica
    address: str         # Non necessario per verifica
    phone: str           # Non necessario per verifica

# CORRETTO: minimizza i dati al minimo necessario
class CitizenEligibilityDTO(BaseModel):
    # Solo un token opaco, non il codice fiscale reale
    pseudonymous_id: str
    is_eligible: bool
    benefit_category: str
    # Nessun dato personale identificativo

# Service layer con minimizzazione
class HealthBenefitService:
    def __init__(self, citizen_repo, pseudonym_service):
        self.citizen_repo = citizen_repo
        self.pseudonym_service = pseudonym_service

    def check_eligibility(self, pseudonymous_id: str, benefit_code: str) -> CitizenEligibilityDTO:
        # Risolve il pseudonimo solo internamente, non lo espone
        real_id = self.pseudonym_service.resolve(pseudonymous_id)

        # Query mirata: solo il dato necessario
        is_eligible = self.citizen_repo.check_benefit_eligibility(
            citizen_id=real_id,
            benefit_code=benefit_code
        )

        return CitizenEligibilityDTO(
            pseudonymous_id=pseudonymous_id,
            is_eligible=is_eligible,
            benefit_category=benefit_code
        )
        # NON ritorna: nome, CF, indirizzo, telefono, email

# Repository con projection query (minimizzazione lato DB)
class CitizenRepository:
    def check_benefit_eligibility(self, citizen_id: str, benefit_code: str) -> bool:
        # SELECT solo la colonna necessaria, non SELECT *
        query = """
            SELECT EXISTS(
                SELECT 1 FROM citizen_benefits
                WHERE citizen_id = {citizen_id}
                AND benefit_code = {benefit_code}
                AND valid_until >= CURRENT_DATE
            )
        """
        return self.db.execute(query, {"citizen_id": citizen_id, "benefit_code": benefit_code}).scalar()

Model 2: Pseudonimizare și tokenizare

Pseudonimizarea (definită la art. 4(5) GDPR) este una dintre măsurile tehnice menționate în mod explicit de art. 25 like adecvate pentru a demonstra conformitatea cu Privacy by Design. Diferă de anonimizare: datele pseudonimizate pot să fie urmărit către persoana interesată prin informații suplimentare păstrate separat, în timp ce datele anonime nu sunt pot fi (și, prin urmare, nu sunt supuse GDPR).

Pentru sistemele PA, pseudonimizarea este adesea preferabilă anonimizării, deoarece vă permite să mențineți trasabilitatea internă (necesară pentru audit și conformitate) protejând în același timp identitatea persoanelor vizate în sisteme front-end și în jurnalele.

# Pattern Pseudonimizzazione con Vault separato
# Architettura: Pseudonym Vault isolato dal sistema principale

import secrets
import hmac
import hashlib
from datetime import datetime, timedelta
from dataclasses import dataclass

@dataclass
class PseudonymRecord:
    pseudonym: str
    real_id: str
    created_at: datetime
    expires_at: datetime
    purpose: str  # Finalità del trattamento (Art. 5(1)(b))

class PseudonymVault:
    """
    Vault isolato che gestisce la mappatura pseudonimo <-> identità reale.
    Accesso ristretto: solo servizi autorizzati con chiave vault.
    Log di ogni accesso per audit GDPR.
    """

    def __init__(self, vault_key: bytes, db_connection):
        self._vault_key = vault_key
        self._db = db_connection

    def create_pseudonym(
        self,
        real_id: str,
        purpose: str,
        validity_days: int = 365
    ) -> str:
        """
        Genera pseudonimo crittograficamente sicuro.
        Usa HMAC-SHA256 con chiave vault per essere deterministico
        (stesso real_id + purpose = stesso pseudonimo) ma non invertibile
        senza la chiave vault.
        """
        # HMAC deterministico: stesso input = stesso output
        # Ma non reversibile senza vault_key
        pseudonym_bytes = hmac.new(
            key=self._vault_key,
            msg=f"{real_id}:{purpose}".encode(),
            digestmod=hashlib.sha256
        ).digest()

        # Converti in stringa URL-safe
        pseudonym = pseudonym_bytes.hex()[:32]  # 128-bit, abbondante

        # Registra nel vault (separato dal DB principale)
        record = PseudonymRecord(
            pseudonym=pseudonym,
            real_id=real_id,
            created_at=datetime.utcnow(),
            expires_at=datetime.utcnow() + timedelta(days=validity_days),
            purpose=purpose
        )
        self._db.insert_pseudonym(record)

        return pseudonym

    def resolve_pseudonym(self, pseudonym: str, requesting_service: str) -> str:
        """
        Risolve pseudonimo -> identità reale.
        Richiede autorizzazione esplicita del servizio richiedente.
        Logga ogni accesso per audit.
        """
        # Audit log obbligatorio
        self._log_resolution_access(
            pseudonym=pseudonym,
            requesting_service=requesting_service,
            timestamp=datetime.utcnow()
        )

        record = self._db.get_pseudonym(pseudonym)

        if not record:
            raise ValueError("Pseudonym not found")

        if datetime.utcnow() > record.expires_at:
            raise ValueError("Pseudonym expired")

        return record.real_id

    def _log_resolution_access(self, pseudonym: str, requesting_service: str, timestamp: datetime):
        """
        Log GDPR-compliant: registra chi ha risolto quale pseudonimo e quando.
        Il log stesso usa solo lo pseudonimo (non l'identità reale).
        """
        self._db.insert_audit_log({
            "action": "PSEUDONYM_RESOLVED",
            "pseudonym_hash": hashlib.sha256(pseudonym.encode()).hexdigest(),
            "requesting_service": requesting_service,
            "timestamp": timestamp.isoformat(),
            "legal_basis": "GDPR Art. 6(1)(e) - Task public interest"
        })

Modelul 3: Managementul consimțământului conform GDPR

Consimțământul (Art. 7 GDPR) trebuie să fie liber, specific, informat și lipsit de ambiguitate. Pentru PA, în majoritatea În unele cazuri, prelucrarea nu se bazează pe consimțământ, ci pe baze juridice diferite (art. 6 alineatul (1) litera (e): sarcină de interes public, o art. 6(1)(c): obligație legală). Cu toate acestea, atunci când consimțământul este baza legală aleasă - de exemplu pentru comunicări marketing, buletine informative sau prelucrare opțională — sistemul de gestionare a consimțământului trebuie să îndeplinească cerințe precise.

Un Platforma de gestionare a consimțământului (CMP) pentru AP trebuie să memoreze: ce a fost acceptat, când, cu care versiunea informațiilor, de pe ce canal și trebuie să permită revocarea la fel de ușoară pe cât a fost prevederea.

-- Schema SQL: Consent Management GDPR-compliant
-- Database separato o schema isolato con accesso controllato

CREATE TABLE consent_purposes (
    purpose_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    code VARCHAR(64) UNIQUE NOT NULL,
    name_it TEXT NOT NULL,
    name_en TEXT,
    description_it TEXT NOT NULL,
    legal_basis VARCHAR(32) NOT NULL,  -- 'consent', 'legal_obligation', 'public_task'
    data_categories TEXT[] NOT NULL,   -- Categorie di dati trattati
    retention_days INTEGER NOT NULL,
    third_parties TEXT[],              -- Destinatari (trasparenza)
    created_at TIMESTAMPTZ DEFAULT NOW(),
    version INTEGER NOT NULL DEFAULT 1,
    is_active BOOLEAN DEFAULT TRUE
);

CREATE TABLE citizen_consents (
    consent_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    -- Pseudonimo, non ID reale
    citizen_pseudonym VARCHAR(64) NOT NULL,
    purpose_id UUID REFERENCES consent_purposes(purpose_id),
    status VARCHAR(16) NOT NULL CHECK (status IN ('granted', 'denied', 'withdrawn')),
    granted_at TIMESTAMPTZ,
    withdrawn_at TIMESTAMPTZ,
    -- Prova del consenso (Art. 7(1): titolare deve dimostrare il consenso)
    proof_channel VARCHAR(32) NOT NULL,    -- 'web_portal', 'mobile_app', 'paper'
    proof_ip_hash VARCHAR(64),             -- Hash dell'IP, non IP raw
    proof_session_id VARCHAR(128),
    privacy_policy_version VARCHAR(16) NOT NULL,
    -- Lingua in cui è stata mostrata l'informativa
    consent_language VARCHAR(8) NOT NULL DEFAULT 'it',
    user_agent_hash VARCHAR(64)
);

-- Indice per query rapide sulla revoca
CREATE INDEX idx_consents_pseudonym ON citizen_consents(citizen_pseudonym, status);

-- Vista per audit: mostra solo dati necessari al DPO
CREATE VIEW consent_audit_view AS
SELECT
    c.consent_id,
    c.citizen_pseudonym,
    p.code AS purpose_code,
    p.name_it AS purpose_name,
    c.status,
    c.granted_at,
    c.withdrawn_at,
    c.proof_channel,
    c.privacy_policy_version
FROM citizen_consents c
JOIN consent_purposes p ON c.purpose_id = p.purpose_id;

-- Funzione per il diritto di revoca (Art. 7(3))
CREATE OR REPLACE FUNCTION withdraw_consent(
    p_citizen_pseudonym VARCHAR(64),
    p_purpose_code VARCHAR(64)
) RETURNS VOID AS $
BEGIN
    UPDATE citizen_consents
    SET
        status = 'withdrawn',
        withdrawn_at = NOW()
    WHERE
        citizen_pseudonym = p_citizen_pseudonym
        AND purpose_id = (
            SELECT purpose_id FROM consent_purposes WHERE code = p_purpose_code
        )
        AND status = 'granted';

    -- Logga l'evento per audit
    INSERT INTO consent_events (
        event_type, citizen_pseudonym, purpose_code, occurred_at
    ) VALUES (
        'CONSENT_WITHDRAWN', p_citizen_pseudonym, p_purpose_code, NOW()
    );
END;
$ LANGUAGE plpgsql;

Model 4: Reținerea automată a datelor și dreptul la ștergere

Principiul „limitării stocării” (Art. 5(1)(e) GDPR) impune ca datele cu caracter personal să fie stocate "într-o formă care să permită identificarea părţilor interesate pe o perioadă de timp care nu depăşeşte realizarea a scopurilor pentru care sunt prelucrate„. În practică, fiecare sistem PA trebuie să implementeze o politică de reținere automat care șterge sau anonimizează datele expirate fără intervenție manuală.

Dreptul la ștergere (art. 17 GDPR), cunoscut sub numele de „dreptul de a fi uitat”, adaugă un nivel suplimentar de complexitate: sistemul trebuie să poată șterge datele unei anumite persoane la cerere, cu respectarea eventualelor excepții (de exemplu, datele necesare pentru a respecta obligațiile legale).

# Data Retention Manager - Python con scheduling automatico
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from dataclasses import dataclass
from enum import Enum
from datetime import datetime, timedelta
from typing import List

class RetentionAction(Enum):
    DELETE = "delete"
    ANONYMIZE = "anonymize"
    ARCHIVE = "archive"

@dataclass
class RetentionPolicy:
    table_name: str
    date_column: str
    retention_days: int
    action: RetentionAction
    legal_basis: str  # Documentazione dell'obbligo legale

# Registro delle politiche di retention (da configurazione, non hardcoded)
RETENTION_POLICIES: List[RetentionPolicy] = [
    RetentionPolicy(
        table_name="citizen_session_logs",
        date_column="created_at",
        retention_days=90,  # 3 mesi per log sessione
        action=RetentionAction.DELETE,
        legal_basis="GDPR Art. 5(1)(e) - Storage limitation"
    ),
    RetentionPolicy(
        table_name="service_requests",
        date_column="completed_at",
        retention_days=2555,  # 7 anni per atti amministrativi
        action=RetentionAction.ANONYMIZE,
        legal_basis="D.Lgs. 82/2005 Art. 40 - Conservazione atti"
    ),
    RetentionPolicy(
        table_name="consent_records",
        date_column="withdrawn_at",
        retention_days=365,  # 1 anno dopo revoca per prova
        action=RetentionAction.DELETE,
        legal_basis="GDPR Art. 7(1) - Prova consenso"
    ),
]

class DataRetentionManager:
    def __init__(self, db, audit_logger):
        self.db = db
        self.audit_logger = audit_logger
        self.scheduler = AsyncIOScheduler()

    async def run_retention_policy(self, policy: RetentionPolicy) -> dict:
        """Esegue una politica di retention e ritorna statistiche."""
        cutoff_date = datetime.utcnow() - timedelta(days=policy.retention_days)
        stats = {"policy": policy.table_name, "action": policy.action.value, "rows_affected": 0}

        if policy.action == RetentionAction.DELETE:
            result = await self.db.execute(
                f"DELETE FROM {policy.table_name} WHERE {policy.date_column} < $1",
                cutoff_date
            )
            stats["rows_affected"] = result.rowcount

        elif policy.action == RetentionAction.ANONYMIZE:
            # Anonymize: sostituisce dati identificativi con hash o NULL
            result = await self.db.execute(
                f"""UPDATE {policy.table_name}
                    SET
                        fiscal_code = 'ANONYMIZED_' || gen_random_uuid()::text,
                        first_name = NULL,
                        last_name = NULL,
                        email = NULL,
                        phone = NULL
                    WHERE {policy.date_column} < $1
                    AND fiscal_code NOT LIKE 'ANONYMIZED_%'""",
                cutoff_date
            )
            stats["rows_affected"] = result.rowcount

        # Audit log obbligatorio per ogni operazione di retention
        await self.audit_logger.log({
            "event": "RETENTION_EXECUTED",
            "policy": policy.table_name,
            "action": policy.action.value,
            "cutoff_date": cutoff_date.isoformat(),
            "rows_affected": stats["rows_affected"],
            "legal_basis": policy.legal_basis,
            "executed_at": datetime.utcnow().isoformat()
        })

        return stats

    async def handle_erasure_request(self, citizen_pseudonym: str, request_id: str) -> dict:
        """
        Gestisce il diritto alla cancellazione (Art. 17 GDPR).
        Verifica le eccezioni prima di procedere.
        """
        # Verifica eccezioni Art. 17(3) - obblighi legali, interesse pubblico, etc.
        exceptions = await self._check_erasure_exceptions(citizen_pseudonym)

        if exceptions:
            # Non cancella, documenta il motivo del diniego
            await self.audit_logger.log({
                "event": "ERASURE_REQUEST_DENIED",
                "citizen_pseudonym": citizen_pseudonym,
                "request_id": request_id,
                "reasons": exceptions
            })
            return {"status": "denied", "reasons": exceptions}

        # Procede con la cancellazione
        tables_affected = []
        for table in ["citizen_session_logs", "consent_records", "service_requests_temp"]:
            rows = await self.db.execute(
                f"DELETE FROM {table} WHERE citizen_pseudonym = $1",
                citizen_pseudonym
            )
            if rows.rowcount > 0:
                tables_affected.append(table)

        await self.audit_logger.log({
            "event": "ERASURE_REQUEST_EXECUTED",
            "citizen_pseudonym": citizen_pseudonym,
            "request_id": request_id,
            "tables_affected": tables_affected,
            "executed_at": datetime.utcnow().isoformat()
        })

        return {"status": "completed", "tables_affected": tables_affected}

DPIA: când este obligatoriu și cum se structurează

La Evaluarea impactului privind protecția datelor (DPIA, Data Protection Impact Assessment) este obligatoriu în temeiul art. 35 GDPR la prelucrarea "poate prezenta un risc ridicat pentru drepturile și libertățile persoane fizice„. Pentru PA italiană, Garantul de confidențialitate a publicat o listă de tratamente care necesită DPIA este obligatorie.

Tratamente PA care necesită DPIA obligatorie

  • Profilare sistematică a cetățenilor (de exemplu, punctaj socioeconomic)
  • Tratament pe scară largă a unor anumite categorii de date (sănătate, judiciar)
  • Supraveghere sistematică a zonelor publice (supraveghere video)
  • Sisteme de potrivire/legare de seturi de date din diferite surse
  • Datele persoanelor vulnerabile (minori, pacienți, solicitanți de azil)
  • Utilizarea inovatoare a tehnologiilor (AI/ML pentru decizii automate Art. 22)
  • Transfer internațional a datelor personale

O DPIA structurată include: descrierea prelucrării și a scopurilor acesteia, evaluarea necesității și proporționalității, identificarea și evaluarea riscurilor pentru drepturile persoanelor vizate și măsurile preconizate pentru abordarea riscurilor (inclusiv garanții și mecanisme de securitate). Implicarea DPO (responsabilul cu protecția datelor) este obligatorie (Art. 35(2)) și DPIA trebuie actualizate atunci când tratamentul se modifică.

Model 5: Înregistrare de audit conform GDPR

O cerință subestimată a GDPR este responsabilitate (responsabilitate, art. 5(2)): proprietarul a tratamentului trebuie să poată demonstra conformitatea. Acest lucru necesită un sistem de înregistrare a auditului care urmărește operațiuni pe date personale, dar care — paradoxal — nu devine ea însăși o sursă a prelucrării excesive a datelor cu caracter personal.

Un jurnal de audit conform GDPR trebuie:

  • Înregistra OMS a accesat ce date și când, folosind pseudonime sau ID-uri de sistem acolo unde este posibil
  • A fi imuabil (numai anexa) pentru a asigura integritatea probelor
  • Aveți propria politică de păstrare (jurnalele nu sunt păstrate pentru totdeauna)
  • Fii protejat de accesul neautorizat (separat de DB principal)
  • Sprijiniți întrebări eficiente pentru a răspunde solicitărilor din partea DPO sau a Autorității Garante
# Audit Logger immutabile con PostgreSQL - append-only tramite trigger
# Usa una tabella separata con accesso write-only dall'applicazione

-- Schema audit log (database o schema separato)
CREATE TABLE gdpr_audit_log (
    log_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    -- Identificatori: pseudonimizzati dove possibile
    subject_pseudonym VARCHAR(64),       -- Chi ha eseguito l'azione
    affected_entity_pseudonym VARCHAR(64), -- Su quale entità
    -- Cosa è successo
    action_type VARCHAR(64) NOT NULL,    -- READ, UPDATE, DELETE, EXPORT, etc.
    resource_type VARCHAR(64) NOT NULL,  -- citizen_record, consent, health_data, etc.
    -- Contesto
    legal_basis VARCHAR(128),            -- Base giuridica del trattamento
    purpose VARCHAR(256),                -- Finalità del trattamento
    -- Metadati tecnici (senza dati personali)
    service_name VARCHAR(128) NOT NULL,
    request_id VARCHAR(128),
    -- Timestamp immutabile
    occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
    -- NON includere: IP raw, user agent completo, payload della request
);

-- Nega UPDATE e DELETE sulla tabella audit (append-only)
CREATE RULE no_update_audit AS ON UPDATE TO gdpr_audit_log DO INSTEAD NOTHING;
CREATE RULE no_delete_audit AS ON DELETE TO gdpr_audit_log DO INSTEAD NOTHING;

-- Funzione trigger per log automatico su tabelle sensibili
CREATE OR REPLACE FUNCTION audit_sensitive_access() RETURNS TRIGGER AS $
BEGIN
    INSERT INTO gdpr_audit_log (
        action_type,
        resource_type,
        subject_pseudonym,
        affected_entity_pseudonym,
        service_name,
        legal_basis
    ) VALUES (
        TG_OP,                          -- INSERT/UPDATE/DELETE
        TG_TABLE_NAME,
        current_setting('app.current_user_pseudonym', true),
        NEW.citizen_pseudonym,
        current_setting('app.service_name', true),
        current_setting('app.legal_basis', true)
    );
    RETURN NEW;
END;
$ LANGUAGE plpgsql SECURITY DEFINER;

-- Applica il trigger alle tabelle sensibili
CREATE TRIGGER audit_health_records
    AFTER INSERT OR UPDATE OR DELETE ON health_records
    FOR EACH ROW EXECUTE FUNCTION audit_sensitive_access();

Arhitectură generală: GDPR-by-Design într-un serviciu PA

Reunind toate modelele descrise, arhitectura unui serviciu PA conform GDPR-by-Design include:

  • Gateway API: Punct de intrare care verifică autentificarea (SPID/CIE), aplică pseudonimizarea și propagă baza legală în contextul solicitării (prin antet sau middleware)
  • Pseudonim Vault: serviciu izolat pentru cartografierea pseudonim-identității, cu acces restricționat și jurnalul de audit al fiecărei rezoluții
  • Microservicii cu minimizarea datelor: fiecare serviciu primește doar datele necesare, expune DTO-uri minime, utilizați interogări de proiecție la DB
  • Serviciul de management al consimțământului: gestionează consimțământul, verifică temeiurile legale, susține revocarea și export de date (portabilitate Art. 20)
  • Programator de retenție: joburi periodice care aplică politici de reținere și gestionează solicitările anulare și să întocmească rapoarte pentru DPO
  • Serviciul de jurnal de audit: numai pentru atașare, separat, cu acces doar pentru scriere din aplicație și numai pentru citire de către DPO/garant

Instrumente și cadre utile pentru GDPR-by-Design în PA

  • OpenDP: Bibliotecă Python pentru confidențialitate diferențială, utilă pentru analize anonimizate
  • Instrumentul de anonimizare a datelor ARX: instrument open source pentru anonimizarea setului de date
  • Mantaua cheii: Furnizor de identitate open source cu suport încorporat pentru gestionarea consimțământului
  • Schița de date: pentru hashing și MinHash, util în pseudonimizarea scalabilă
  • PgAudit: Extensie PostgreSQL pentru înregistrarea de audit la nivel de bază de date
  • Designeri Italia: orientări oficiale AgID privind confidențialitatea prin proiectare pentru PA
  • Ghidul CNIL de confidențialitate prin proiectare: metodologia practică a autorității franceze, aplicabilă în Italia

Rolul DPO și colaborarea cu echipa de dezvoltare

În temeiul art. 37 GDPR, numirea responsabilului cu protecția datelor (DPO) este obligatorie pentru toate autoritățile publice şi organismele publice (cu excepţia instanţelor judecătoreşti în exercitarea funcţiilor jurisdicţionale). DPO nu este doar o figură de conformitate: pentru echipele de dezvoltare, el reprezintă un consultant intern în protecția datelor care trebuie implicat încă din fazele inițiale ale unui proiect.

În practică, echipa de dezvoltare ar trebui să:

  • Implicați DPO-ul în revizuirea arhitecturii atunci când procesează datele cu caracter personal
  • Opțiunile de proiectare a confidențialității documentelor în Arhitecture Decision Records (ADR)
  • Includeți verificări de conformitate cu GDPR în definițiile user story a terminat
  • Efectuați o evaluare a riscului de confidențialitate pentru fiecare funcție nouă care introduce prelucrarea datelor cu caracter personal
  • Păstrați Registrul de prelucrare (Art. 30) actualizat în mod automat, acolo unde este posibil

Concluzii și pașii următori

GDPR-by-Design nu este o listă de verificare birocratică care trebuie bifată la sfârșitul dezvoltării: este o abordare arhitecturală care, dacă este integrat încă din primele etape ale proiectului, produce sisteme mai sigure, mai transparente și mai robuste. Tiparele descrise în acest articol — minimizarea datelor, pseudonimizarea, gestionarea consimțământului, păstrarea înregistrare automată, de audit — se aplică oricărui serviciu digital al PA italiană, de la unul simplu pagină de colectare a consimțământului pentru un buletin informativ instituțional până la sisteme complexe, cum ar fi fișa medicală platforme de plată electronice sau digitale.

În următorul articol al acestei serii vom analiza modul de implementare a interfețelor de utilizator accesibile pentru al doilea PA standardul WCAG 2.1 AA: o altă cerință de reglementare care, la fel ca GDPR, îi recompensează pe cei care îl integrează încă din faza de proiectare.

Articole similare din această serie

  • GovTech #01: eIDAS 2.0 și EUDI Wallet - identitate digitală europeană și acreditări verificabile
  • GovTech #02: OpenID Connect pentru identitate guvernamentală - SPID, CIE și cele mai bune practici de securitate
  • GovTech #05: UI accesibilă pentru implementarea PA - WCAG 2.1 AA
  • GovTech #06: Integrare API guvernamentală - SPID, CIE și pagoPA