← Torna a tutti gli articoli

Catene di hash e rilevamento delle manomissioni: come un solo byte modificato invalida un intero archivio

SealDoc Team · · 9 min di lettura

Quando qualcuno dice che un archivio documentale è “tamper-evident”, cioè che rende rilevabile ogni manomissione, l’affermazione è precisa: qualsiasi modifica a qualsiasi record produce un’incoerenza rilevabile. Non “tamper-proof”, cioè inalterabile: quella è un’affermazione diversa e più forte. Tamper-evident significa che, se l’archivio è stato modificato, puoi trovare la modifica.

Le catene di hash sono la costruzione standard per ottenere questa proprietà. Non sono una novità (il concetto precede la blockchain di decenni), ma sono ampiamente fraintese, il che porta sia a un eccesso di fiducia sia a un utilizzo insufficiente.

Questo articolo spiega come funzionano le catene di hash, cosa garantiscono, cosa non garantiscono e perché le specifiche scelte implementative contano.

Cos’è un hash crittografico

Una funzione hash crittografica prende un input di lunghezza arbitraria e produce un output di lunghezza fissa, chiamato hash o digest. SHA-384 produce un output di 384 bit (48 byte), tipicamente rappresentato come 96 caratteri esadecimali.

Tre proprietà rendono le funzioni hash utili per il rilevamento delle manomissioni:

Determinismo. Lo stesso input produce sempre lo stesso output. Se calcoli due volte l’hash dello stesso documento, ottieni lo stesso hash.

Effetto valanga. Una piccola modifica dell’input produce un output completamente diverso. Modificare un byte in un documento di 10.000 byte produce un hash che non ha alcuna somiglianza con l’originale. Non c’è modo di prevedere come sarà il nuovo hash.

Unidirezionalità. Dato un hash, è computazionalmente impraticabile ricostruire l’input. Non puoi risalire dall’hash al documento.

La terza proprietà è ciò che rende vincolanti le catene di hash: una volta pubblicato o registrato un hash, ti sei impegnato sul contenuto che lo ha prodotto senza rivelare il contenuto stesso.

La costruzione di base

Una catena di hash collega una sequenza di eventi in modo che ogni evento dipenda da tutti gli eventi precedenti.

Nell’implementazione di SealDoc, un evento probatorio contiene:

  • Il tipo di evento (ad es. vault.ingested, anchor.rfc3161)
  • Un numero di sequenza
  • Un timestamp
  • I dettagli specifici dell’evento (come JSON canonico)
  • L’hash dell’evento precedente
  • L’hash di questo evento, calcolato su tutti i campi precedenti

L’hash di ogni evento include l’hash dell’evento precedente. Ciò significa che per riprodurre l’hash dell’evento N ti servono il contenuto esatto dell’evento N e l’hash esatto dell’evento N-1. L’hash dell’evento N-1 dipendeva dall’evento N-2, e così via fino al primo evento.

Il primo evento usa come “hash precedente” un valore genesis fisso, una costante nota che chiunque può verificare.

Si crea così una catena in cui:

Hash(Event 1) = H("vault.ingested" | seq:1 | ts:... | details:... | genesis)
Hash(Event 2) = H("anchor.rfc3161" | seq:2 | ts:... | details:... | Hash(Event 1))
Hash(Event 3) = H("vault.storage-lock.applied" | seq:3 | ts:... | details:... | Hash(Event 2))

Cosa succede quando la manometti

Supponiamo che un avversario voglia modificare i dettagli dell’Evento 1. Cambia un campo dell’evento, poi ricalcola l’hash dell’Evento 1. Il nuovo hash è diverso dall’originale.

Ma l’hash dell’Evento 2 è stato calcolato usando l’hash originale dell’Evento 1. L’avversario ora deve ricalcolare l’hash dell’Evento 2 usando il nuovo hash dell’Evento 1. Questo produce un hash diverso per l’Evento 2.

Ora l’Evento 3 ha l’hash precedente sbagliato. E così via per ogni evento successivo.

Per rendere la modifica non rilevabile, l’avversario deve ricalcolare gli hash di ogni evento dal punto manomesso in avanti. In un sistema locale e autosufficiente, questo è possibile. La catena da sola non lo impedisce.

Ecco perché l’ancoraggio è importante.

Ancoraggio: rendere la catena verificabile dall’esterno

Una catena di hash che esiste solo nel tuo database dimostra l’integrità all’interno del tuo sistema. Un avversario che controlla il tuo database può riscrivere l’intera catena. La catena deve essere ancorata a qualcosa al di fuori del tuo controllo.

Il meccanismo standard è un timestamp RFC 3161. Il flusso funziona così:

  1. Al momento della creazione del documento, calcola l’hash dell’evento probatorio.
  2. Invia quell’hash a una Time Stamping Authority (TSA) indipendente.
  3. La TSA firma una risposta contenente il tuo hash, il timestamp della TSA e l’identità della TSA. Questa risposta firmata è il token di timestamp.
  4. Conserva il token di timestamp insieme alla catena di hash.

Il token di timestamp è firmato con la chiave privata della TSA. La catena di certificati della TSA è verificabile pubblicamente. Chiunque disponga del documento, dell’hash originale e del token di timestamp può verificare in modo indipendente che il documento esisteva in quello stato in quel momento, senza doversi fidare di te in alcun modo.

Ora il problema dell’avversario è più difficile. Per modificare l’Evento 1 senza essere scoperto, deve:

  1. Modificare l’evento e ricalcolare tutti gli hash a valle.
  2. Ottenere da una TSA affidabile un nuovo timestamp RFC 3161 per il nuovo hash.

Il secondo passaggio è impossibile a posteriori. Il timestamp della TSA ha un orario incorporato. Un timestamp che attesti che il documento modificato esisteva all’orario originale dovrebbe essere emesso dalla TSA proprio a quell’orario originale, cosa che l’avversario non può organizzare a posteriori.

Questo è ciò che “tamper-evident” significa nella pratica: non che la modifica sia impedita a livello fisico, ma che qualsiasi modifica che un avversario voglia far passare inosservata richiede di compromettere la firma della TSA indipendente oppure di riscrivere la storia, due cose entrambe computazionalmente impraticabili.

Perché due digest, e dove si trova ciascuno

SHA-256 è l’algoritmo di hash più usato per questa classe di applicazioni. SealDoc lo usa per la catena di elaborazione e per il manifest del pacchetto, e SHA-384 per il registro delle prove. Entrambi vengono eseguiti per ogni documento; rispondono a domande diverse.

La catena di elaborazione non può scegliere liberamente. Il suo digest è anche la chiave di storage, ed è l’impronta del messaggio che la Time Stamping Authority firma, così la linea delle prove va dai byte, attraverso l’impronta, fino al token. Cambiarlo significherebbe migrare ogni localizzatore archiviato e ogni token esistente, non modificare un’impostazione.

Il registro delle prove è stato costruito più tardi e non ha un vincolo di questo tipo, ed è per questo che usa il digest più lungo.

La differenza pratica è il margine. SHA-256 è attualmente considerato sicuro, ma le raccomandazioni crittografiche evolvono. SHA-384 appartiene alla stessa famiglia SHA-2 e viene calcolato in modo identico, solo con uno stato interno più grande. Per archivi con lunghi periodi di conservazione (7 anni per le fatture IVA nell’UE, fino a 20 anni per alcuni documenti del settore pubblico), il margine aggiuntivo conta.

Il digest più lungo riduce anche la probabilità (già trascurabile) di collisioni di hash, in cui due documenti diversi producono lo stesso hash. Per gli archivi di conformità questa è una proprietà significativa: due fatture diverse non dovrebbero mai produrre lo stesso identificatore.

Verificare la catena

La verifica procede a ritroso a partire dall’evento più recente. Dato un insieme di eventi in ordine di sequenza:

  1. Per ogni evento, ricalcola l’hash usando i campi memorizzati: tipo di evento, numero di sequenza, timestamp, dettagli e hash precedente.
  2. Confronta l’hash ricalcolato con l’hash memorizzato. Se corrispondono, il contenuto dell’evento non è stato modificato da quando l’hash è stato calcolato.
  3. Verifica che il previousHash di ogni evento corrisponda all’hash memorizzato dell’evento che lo precede. Se corrispondono, la catena è integra.
  4. Per ogni evento che porta un ancoraggio con timestamp RFC 3161, verifica il token di timestamp rispetto alla catena di certificati della TSA.

L’endpoint GET /api/vault/{recordId}/verify di SealDoc ricalcola ogni hash, controlla ogni collegamento, verifica le firme degli eventi e riporta l’ancoraggio temporale, con un dettaglio per ogni evento:

{
  "chainValid": true,
  "eventCount": 3,
  "events": [
    {
      "sequenceNo": 1,
      "eventType": "vault.ingested",
      "hashVerified": true,
      "chainLinkVerified": true,
      "signaturePresent": true,
      "signatureVerified": true
    }
  ]
}

hashVerified significa che l’hash ricalcolato corrisponde all’hash memorizzato. chainLinkVerified significa che il puntatore all’hash precedente è coerente. signatureVerified significa che la firma ECDSA sull’hash dell’evento è valida rispetto alla chiave di firma nota.

Una catena in cui ogni evento restituisce hashVerified: true e chainLinkVerified: true è una catena in cui nessun dato memorizzato è stato modificato. I timestamp di ancoraggio forniscono la prova esterna, verificabile tramite la TSA, di quando si è verificato ciascun evento.

Cosa la catena non garantisce

La rilevabilità delle manomissioni è una proprietà specifica e circoscritta. Vale la pena essere precisi su cosa copre e cosa no.

Non impedisce la cancellazione. Una catena di hash rileva la modifica dei record esistenti, ma non può rilevare che un record è stato cancellato. Se l’Evento 2 di una catena di cinque eventi viene rimosso del tutto, la catena si spezza, ma solo se chi verifica sa che dovrebbero esserci cinque eventi, non quattro. Impedire la cancellazione è una questione separata, a livello di storage, come lo storage WORM.

Non impedisce al sistema di origine di mentire. Se il documento era corrotto prima di entrare nella pipeline, la catena di hash si impegna su quella versione corrotta. La catena dimostra l’integrità dal momento dell’acquisizione in avanti, non dal momento della creazione. Ecco perché la validazione (controllo di conformità PDF/A, validazione dello schema Factur-X) avviene prima che l’hash venga registrato.

La catena è forte solo quanto i suoi ancoraggi. Una catena senza ancoraggi RFC 3161 esterni è un sistema che si autocertifica. Dimostra la coerenza interna, ma non il vincolo temporale. Per qualsiasi caso d’uso di conformità serio sono necessari timestamp ancorati a una TSA indipendente.

Le conseguenze pratiche per gli sviluppatori

Se stai costruendo una pipeline documentale e ti serve la rilevabilità delle manomissioni, l’implementazione è semplice:

  1. All’acquisizione, calcola un hash del documento con SHA-256 o SHA-384.
  2. Invia l’hash a una TSA RFC 3161 e conserva il token di timestamp restituito.
  3. Per ogni evento successivo, collega l’hash dell’evento all’hash dell’evento precedente.
  4. Conserva la catena in uno storage append-only (nessun update o delete sulla tabella degli eventi).
  5. Esponi un endpoint di verifica che ricalcola e controlla la catena su richiesta.

La complessità concettuale è bassa. La complessità implementativa deriva dagli aspetti operativi: gestione delle chiavi, affidabilità della TSA, migrazione della catena se cambi l’algoritmo di hash, e gestione del caso in cui l’invio alla TSA fallisca a metà transazione.

SealDoc gestisce questi aspetti come infrastruttura, così le pipeline che instradano i documenti attraverso l’API ottengono la catena senza doverla implementare. Ma se la costruisci da solo, quanto descritto sopra è la costruzione minima praticabile.


Il SealDoc Evidence Vault produce un log di eventi a catena di hash per ogni documento e richiede un timestamp RFC 3161 a una Time Stamping Authority indipendente dell’UE. La catena e i timestamp sono verificabili tramite GET /api/vault/{recordId}/verify senza doversi fidare dell’infrastruttura SealDoc.


← Torna a tutti gli articoli