Esporta (0) Stampa
Espandi tutto

Sicurezza dei dati: diversi aspetti

Da Maurizio Cunico

Il dato: attorno al dato gira tutto il nostro lavoro.

Pervasivo e invasivo, il dato ci accompagna in ogni istante e ci sollecita continue revisioni di strategia e di innovazione.

Ma questa sua presenza continua, questa familiarità che abbiamo con lui ci porta a sottovalutarlo, a dimenticarlo, a dimenticarci che è un oggetto complesso, a volte sfuggente, a volte malandrino.

Partiamo dall’inizio.

Il dato è il pane dell’informatica. Ogni applicazione opera su dati, ogni operazione è relativa a dati.

Il dato è gestito dall’applicazione che fornisce una funzionalità ad un utente.

Se la cosa fosse così e basta, sarebbe sufficiente controllare le prestazioni del sistema.

Così non è:

  • alcuni utenti devono accedere ai dati e altri non devono poterli vedere;

  • alcuni devono poter vedere tutti i dati presenti e altri devono poter vedere solo alcuni dati specifici;

  • alcuni devono vedere un dato in tutta la sua storia e altri solo in uno specifico stato;

  • alcuni possono operare sul dato a tutto tondo altri hanno modalità di accesso limitato.

I dati devono essere gestiti attraverso dei “motori di gestione” che possono essere realizzati in proprio o possono essere dei DataBase Management System.

I motori, sia quelli costruiti su misura che di mercato, devono farsi carico di una serie di problemi che possono essere semplicemente identificati in questa lista

  • Accesso (sicurezza) ai dati

  • Integrità dei dati

  • Distribuzione dei dati

  • Disponibilità dei dati

Accesso ai dati / Sicurezza dei dati

La sicurezza del dato è data primariamente dal controllo dell’accesso.

In realtà la sicurezza si dipana tra tre livelli:

  • Sicurezza nella trasmissione e nel trasferimento dei dati

  • Sicurezza nell’accesso alle applicazioni di gestione

  • Sicurezza nell’accesso ai dati

Per il primo aspetto non abbiamo grandi problemi, il dato può essere trasferito con diversi protocolli, ma tutti questi hanno, chi più e chi meno, supporti alla gestione della sicurezza.

Il concetto base è quello di trasferire i dati in modo cifrato.

Per molto tempo questo è sembrato l’anello debole della catena della sicurezza e, di conseguenza, è l’area in cui più si è fatto.

Senza entrare nei dettagli possiamo presupporre, al fine di queste note, che questo non sia un problema.

Il secondo problema, quello relativo al controllo di sicurezza nell’accesso all’applicazione, è tipicamente un problema “banale”, nel senso che una specifica logica applicativa è sufficiente a profilare gli utenti e fornire a loro il corretto accesso.

Per ultimo, il problema della gestione della sicurezza nell’accesso al dato vero e proprio, viene elegantemente risolto attraverso gli strumenti nativi dei database relazionali o con un approccio applicativo.

Ho scorso velocemente questi primi aspetti che ritengo più facilmente gestibili.

Integrità dei dati

Il cuore del problema è nell’integrità dei dati.

Il dato nasce e vive una propria vita in cui viene letto, modificato, cancellato.

Se il dato è maneggiato sempre dallo stesso utente ed è mantenuto in un sistema “protetto” non ha grossi problemi.

I problemi nascono invece quando i dati sono maneggiati da diversi utenti.

Il problema è noto come il problema della concorrenza sui dati.

Cosa succede se due utenti agiscono sullo stesso dato?

La concorrenza viene gestita, sostanzialmente, in due modalità distinte.

Il lock pessimistico e il lock ottimistico.

Il lock pessimistico dice: io prendo in carico un dato, lo rendo indisponibile a chiunque altro, lo lavoro e quando ho finito lo rilascio alla piena disponibilità di tutti.

Apparentemente questa è una soluzione esemplare al problema.

Ma risolve ogni problema? Cosa succede se il dato viene bloccato da un utente che interrompe il lavoro per rispondere a una telefonata? Nessuno può operare sul dato, o su dati che da questo dipendono direttamente, creando una situazione di stallo incontrollabile.

Il lock pessimistico funziona bene solo se il blocco dei dati è istantaneo e controllato. Ovviamente se siamo di fronte ad una operazione un po’ complessa questo non è possibile.

Inoltre esiste il problema del dead-lock.

Il dead-lock è una situazione in cui due utenti operano con lock pessimistico su due entità che, per essere singolarmente modificate, devono poter modificare anche l’altra.

Se due utenti eseguono delle transazioni, il primo sull’entità A, che blocca, e l’altro sull’entità B, che blocca, quando il primo utente accede all’entità B la trova bloccata e viceversa il secondo che tenta di accedere ad A, ma la trova bloccata, ciascuno non rilascia l’altra aspettando che si liberi, ma tutti e due aspettano per sempre.

I database relazionali sono sufficientemente efficienti da gestire queste situazioni con strategie di uscita, ma il problema di fondo rimane.

Il lock ottimistico dice:

  • io mi prendo il dato e lo lavoro

  • metto da parte qualche informazione che mi permetta di capire se qualcun altro, contemporaneamente a me, interviene su questo

  • quando cerco di salvarlo posso sapere se è ancora nelle condizioni in cui l’ho trovato o è stato, nel frattempo, modificato

  • se il dato risulta modificato nel frattempo devo farmi carico della decisione

    • inserire comunque il mio dato modificato perdendo le eventuali modifiche apportate

    • o ripartire dal dato modificato da altri per rilavorarlo.

Bene, questa è una soluzione molto pulita, ma decisamente più complessa da gestire.

Date le due soluzioni rimane da affrontare un problema più complesso.

Quali sono i casi in cui abbiamo davvero concorrenza sui dati?

Ad esempio, se accedo a un magazzino per prelevare un articolo, devo verificare la giacenza e ho bisogno di conoscere il dato reale. Ho bisogno di bloccare la disponibilità del pezzo sino a che non esaurisco tutte le operazioni necessarie al prelievo del pezzo, in modo di evitare di operare su una disponibilità che non corrisponde al reale.

Ma se sto accedendo ai dati anagrafici di un cliente, ho davvero bisogno di gestire la concorrenza?

La prima risposta è: ovvio che sì, se io cambio l’indirizzo, nessuno lo deve cambiare contemporaneamente a me.

Problema: chi definisce quale è l’indirizzo giusto? Quello che scrivo io o quello che scrive qualcun altro? In realtà quello che succede è che quello buono è l’ultimo che viene inserito.

Allora il problema non è informatico ma di ordine squisitamente organizzativo.

Se due persone, nella stessa azienda, operano contemporaneamente sullo stesso dato siamo di fronte ad un serio problema organizzativo:

  • nella migliore delle ipotesi le due persone stanno facendo la stessa cosa sugli stessi dati e quindi l’azienda paga inutilmente almeno una delle due,

  • nella peggiore le due persone stanno inserendo dati diversi e quindi, oltre a pagare due persone per fare la stessa cosa, abbiamo anche una totale indeterminazione sul dato. Quale è quella vero? Non si sa.

Quindi come informatici dobbiamo fare un passo il là, verso il mondo dell’organizzazione.

Ogni volta che ci viene chiesto di gestire una concorrenza dei dati dobbiamo capire che tipologia di problema andiamo ad affrontare.

Se esiste, ad esempio giacenza di magazzino – prenotazione di un posto od oggetto a disponibilità definita – etc…, sceglieremo la strategia che riterremo più corretta, altrimenti qualsiasi soluzione è un palliativo che non risolverà realmente il problema e “il vostro software non funziona!”.

Integrità Referenziale

Una volta affrontato il problema della concorrenza sui dati ci appare un nuovo problema, quello dell’integrità referenziale degli stessi.

Per integrità referenziale si intende che due istanze presenti in due entità e correlate tra di loro devono essere sempre coerenti tra di loro.

Ad esempio se ho la una anagrafica di un prodotto che è classificato attraverso una tabella di categorie valide, non mi deve essere permesso di cancellare una categoria sinché sia presente anche un solo prodotto che sia catalogato con quella categoria. Se così non fosse mi risulterebbe un prodotto con una categoria che non esiste.

L’integrità referenziale serve a garantire che questa coerenza di dati venga mantenuta.

Abbiamo diversi tipi di azioni per garantire l’integrità.

Queste possono essere così identificate:

  • Cascade – Ogni volta che una istanza in una entità padre subisce un evento (ad esempio viene cancellata), ogni istanza collegata in una entità figlia deve subire lo stesso evento (ad esempio essere cancellata).

  • Restrict – la cancellazione di una istanza in una entità padre non è ammessa se esiste una o più istanza collegata in una entità figlia, oppure la cancellazione di una istanza figlia è vietata se questa è collegata ad una istanza dell’entità padre.

  • Set Null – Se l’istanza nella entità padre viene cancellata, l’attributo in foreign key di ogni istanza correlata nell’entità figlia deve essere modificata in NULL.

  • Set Default – Ogni volta che una istanza nell’entità padre viene cancellata, l’attributo di foreign key in ogni istanza correlate nelle entità figlio viene modificata a un valore di default definito.

Vediamo alcuni esempi di Integrità referenziale programmatica nell’ambito di Microsoft SQL Server su un piccolo database di due entità.

Script Database di esempio

CREATE TABLE Padre (IdPadre   int NOT NULL)
ALTER TABLE Padre ADD PRIMARY KEY CLUSTERED (IdPadre ASC)

CREATE TABLE Figlio (IdFiglio    int NOT NULL, IdPadre   int NOT NULL)
ALTER TABLE Figlio ADD PRIMARY KEY CLUSTERED (IdFiglio ASC)

ALTER TABLE Figlio ADD FOREIGN KEY (IdPadre) REFERENCES Padre  (IdPadre)

Esempi di Integrità referenziale

Quando viene cancellato il padre, automaticamente, viene cancellato anche il figlio

create trigger trDELETE_Padre on Padre for DELETE as
begin
  declare  @errno   int,
           @errmsg  varchar(255)
    /* Padre in relazione con Figlio ON PARENT DELETE CASCADE */
    /* PARENT_TABLE="Padre", CHILD_TABLE="Figlio", FK_COLUMNS="IdPadre" */
    delete Figlio
      from Figlio,deleted
      where
        Figlio.IdPadre = deleted.IdPadre
    return
error:
    raiserror @errno @errmsg
    rollback transaction
end

Quando viene creato un padre, automaticamente viene inserito un nuovo figlio

create trigger trINSERT_Padre on Padre for INSERT as
begin
  declare  @IdFiglio int,
           @IdPadre  int,
           @errno   int,
           @errmsg  varchar(255)
Select @IdFiglio = coalesce(max(idFiglio), 0) + 1 from Figlio
Select @IdPadre = IdPadre from inserted 
Insert into Figlio (IdFiglio, IdPadre) values (@IdFiglio, @IdPadre)
  return
error:
    raiserror @errno @errmsg
    rollback transaction
end

Quando il padre viene modificato automaticamente viene modificato anche il figlio

create trigger trUPDATE_Padre on Padre for UPDATE as
begin
  declare  @numrows int,
           @nullcnt int,
           @validcnt int,
           @insIdPadre int,
           @errno   int,
           @errmsg  varchar(255)
  select @numrows = @@rowcount
  if update(IdPadre)
  begin
    if @numrows = 1
    begin
      select @insIdPadre = inserted.IdPadre
        from inserted
      update Figlio
      set Figlio.IdPadre = @insIdPadre
      from Figlio,inserted,deleted
      where Figlio.IdPadre = deleted.IdPadre
    end
    else
    begin
      select @errno = 30006,
             @errmsg = 'Non è possibile aggiornare in cascata (CASCADE) 
il Padre perchè sono coinvolte più righe'
      goto error
    end
  end
  return
error:
    raiserror @errno @errmsg
    rollback transaction
end

Se esiste almeno un figlio il padre non può essere cancellato

create trigger trDELETE_Figlio on Figlio for DELETE as
begin
  declare  @errno   int,
           @errmsg  varchar(255)
    if exists (select * from deleted,Padre
      where
        deleted.IdPadre = Padre.IdPadre and
        not exists (
          select * from Figlio
          where
            Figlio.IdPadre = Padre.IdPadre
        )
    )
    begin
      select @errno  = 30010,
             @errmsg = 'Non è possibile CANCELLARE l’ultimo Figlio di un Padre'
      goto error
    end
    return
error:
    raiserror @errno @errmsg
    rollback transaction
end

Integrità delle informazioni

Oltre all’integrità dei dati abbiamo un altro problema da affrontare, quello dell’integrità delle informazioni.

Non ha alcun senso che mi spenda per garantire che un padre non venga cancellato in presenza di almeno figlio, se poi l’informazione, che il sistema deve esprimere, perde di significato nel momento che cancello l’ultimo figlio di un padre.

La gestione dell’integrità delle informazioni è un problema che si affronta in logica applicativa e non tanto nel database e, spesso, è decisamente complessa.

Un esempio: ho una entità Padre, con PK la matricola del dipendente, che è relata ad un’altra entità Figlia con una relazione di FK. Se ho bisogno di cancellare il Padre non lo posso fare sinché esiste almeno un figlio. Tuttavia se il figlio è un dato “reale”, ad esempio il rilevamento della presenza di un impiegato, non lo posso cancellare e questo mi obbliga a cancellare il padre solo “logicamente”, ovvero l’istanza permane nel database anche se non è più gestibile e può solo essere letta nel contesto, ad esempio, della reportistica.

Il numero di matricola dell’impiegato cancellato “logicamente” non potrà essere riutilizzato anche se “cancellato” perché è presente nella tabella figlia con un significato ben preciso. Questo esempio è semplice, tuttavia molte sono le situazioni in cui questo tipo di problematica si presente e deve essere trattata con il massimo dell’attenzione.

L’importante è di mantenere sempre un controllo lucido sul dato che si gestisce, prestando sempre una grande attenzione agli automatismi che si possono applicare.

Il meccanismo dell’Integrità referenziale può portare a spiacevoli sorprese se attivato senza le giuste cautele.

Come esempio limite, potrei avere un trigger sulla tabella A che a fronte della cancellazione dell’istanza N cancella l’istanza NR sulla tabella B, la quale ha un trigger che cancella l’istanza N + 1 della Tabella A, la quale cancella l’istanza NR + 1 di B che cancella la N + 2 di A e così via…

Cancellando un singolo record potremmo trovarci con il database vuoto.

NB. In realtà, l’esempio così come sopra descritto, non produrrebbe alcun risultato in quanto il meccanismo delle query ricorsive in SQL Server limita il numero di annidamenti possibili. Tuttavia con meccanismi applicativamente un po’ più indiretti e “normali”, dal punto di vista applicativo, il paradosso di cancellare un record e vedersi svuotare l’intero database è potenzialmente possibile.

Distribuzione dei dati

A questo punto, se il dato è in un solo posto, abbiamo risolto gran parte dei nostri problemi, d’altra parte se il dato è distribuito, siamo solo all’inizio dei nostri problemi.

Sono possibili diversi scenari:

  • Abbiamo una sede primaria del dato che ne mantiene la “proprietà” e il controllo (master). Tutti riferiscono alla sede primaria per le operazioni di inserimento e aggiornamento. Oltre alla sede primaria sono presenti altre sedi secondarie a cui riferiscono diversi altri utenti solo per le operazioni di lettura su copie dei dati (slave).

    • Vantaggi il dato è sicuro, protetto e certo. L’accesso distribuito in lettura è performante ed efficiente. Non ci sono problemi di consistenza: nella peggiore delle ipotesi si procede al totale ripristino dei dati in sedi slave a partire dai dati nella sede master.

    • Svantaggi l’aggiornamento viene effettuato solo nella sede master creando un potenziale collo di bottiglia, il tempo tra l’inserimento del dato su master e la sua disponibilità sugli slave può essere lungo e comunque non omogeneo.

  • Abbiamo una sede primaria del dato che riceve copia in continuo dei dati che sono gestiti in sedi secondarie. Il dato diventa un dato master solo dopo che è stato trasferito alla sede centrale e da qui ridistribuito a tutte le sedi periferiche. Dal momento dell’acquisizione del dato al momento in cui diventa master, lo stesso è in uno stato intermedio ed è disponibile solo per la sede in cui vien lavorato.

    • Vantaggi il dato è sicuro, protetto e certo. L’accesso è distribuito e quindi performante.

    • Svantaggi il tempo tra cui il dato è inserito e il momento in cui è disponibile a tutti può essere lungo e, soprattutto, non omogeneo, il periodo tra l’acquisizione del dato e la sua certificazione nell’area master è un periodo di dato non certo

  • Più sedi operano in assoluta autonomia nell’acquisizione e nella gestione dei dati. Periodicamente i dati acquisiti vengono trasferiti in copia alle altre sedi. Tutte le sedi sono paritarie.

    • Vantaggi i dati operati nella singola sede sono sempre disponibili e con prestazioni al massimo possibile

    • Svantaggi i dati sono certi solo per singola sede ma non su base complessiva. I dati sono distribuiti ma sono, a tutti gli effetti, dati partizionati, le operazioni di backup e di manutenzione in genere sono più complesse ed meno “certe”, la presenza di un dato ma soprattutto la sua assenza non è mai certificata.

La corretta strategia sarà scelta in base ad una serie di elementi applicativi e organizzativi che dovranno tenere conto della banda di trasmissione, degli aspetti di disponibilità necessaria, della necessità di operare sui dati con continuità o solo raramente, etc…

In un contesto di dati distribuiti il problema dell’integrità può raggiungere livelli di complessità notevoli.

La complessità logica dell’implementazione dell’integrità dovrà passare primariamente da aspetti di carattere organizzativo e di processo e, solo dopo aver affrontato e risolto questi, si potrà pensare al miglior approccio tecnologico per dare la corretta risoluzione al problema.

Non bisogna mai dimenticare che il dato non è un oggetto da riporre ordinatamente nel miglior scaffale digitale che esista ma è cosa viva ed è il business; va seguito e curato nel contesto della sua esistenza come elemento di business e non come numero o stringa.

Disponibilità dei Dati

Per concludere queste brevi note bisogna spendere almeno due parole sul problema della disponibilità dei dati.

I dati, come abbiamo ribadito, servono per lavorare, per produrre e quindi devono essere sempre disponibili.

Abbiamo due tipi di disponibilità: la disponibilità in termini di orario (every time) e la disponibilità in termini di locazione (everywhere).

Ma per avere una disponibilità di 24 ore al giorno per 7 giorni alla settimana devo pagare dei prezzi.

Devo avere un sistema che sia disponibile 24/7, devo avere personale pronto a intervenire, ma soprattutto devo avere persone che utilizzano i dati con queste tempistiche.

Spesso si è rincorsa la mitica formula 24/7 per servizi che non avevano giustificazione alcuna a questa disponibilità, spesso – come sempre più spesso succede – non si rincorre una esigenza di business quanto una moda.

È necessario che un servizio erogato da una banca ai propri clienti sia in funzione alle 3 della mattina? Certamente qualche cliente potrà anche eseguire operazioni a quell’ora, ma sarà giustificato il costo?

È chiaro che una applicazione Web con clientela internazionale su diversi fusi orari può benissimo essere su logiche di disponibilità senza interruzioni, tuttavia nella realtà della maggior parte applicazioni che si realizzano in Italia oggi questa non è una vera esigenza.

La disponibilità everywhere chiede di rendere disponibile il dato attraverso qualsiasi strumento digitale in qualsiasi luogo.

Questo è squisitamente un problema applicativo e di periferica.

Il dato è facilmente spendibile sulle diverse periferiche e può essere sempre trovato il modo per renderlo usabile.

Conclusioni

Per concludere, come credo si sia capito, il dato importantissimo, è il centro del nostro lavoro ed è la causa di una certa quantità di “mal di testa”.

Il dato deve essere trattato con molta attenzione e rispetto, anche perché, se maltrattato, può essere causa di seri problemi e di pessime figure.


Mostra:
© 2014 Microsoft