Skip to main content
  1. Concetti/

Hashing, HMAC e Password Storage - Integrita' e Autenticazione

Alessio Barnini
Author
Alessio Barnini
Table of Contents

Cos'e' l'Hashing
#

Una funzione di hashing prende un input di qualsiasi dimensione e produce un output di lunghezza fissa (il digest) in modo deterministico e non invertibile. E' la base dell'integrita' dei dati: se anche un solo byte del file cambia, l'hash cambia completamente. Non e' crittografia — non serve una chiave e non si decifra nulla.

hashing-overview.webp

Funzione one-way che trasforma un input di qualsiasi dimensione in un digest di lunghezza fissa. Usato per verificare integrita' dei dati. Non e' cifratura — non c'e' chiave, non c'e' decifratura.

TL;DR
#

Hashing risolve una domanda: "questo dato e' arrivato intatto?". Non risponde a "chi l'ha mandato?" (serve HMAC o firma digitale) e non protegge la riservatezza (serve cifratura).

  1. SHA-256: 256 bit, 64 char hex. Standard NIST. Per integrita' file, firme digitali, TLS.
  2. SHA-3 (Keccak): design diverso da SHA-2, concorso NIST 2015. Alternativa se SHA-2 fosse compromessa.
  3. MD5: 128 bit, cracked 2004. Solo per checksum veloci non crittografici.
  4. SHA-1: deprecated 2017 (SHAttered attack). Non usare per sicurezza.

Gli hash si leggono in esadecimale: 1 char hex = 4 bit. SHA-256 = 256 bit = 64 char hex.


HMAC
#

HMAC (Hash-based Message Authentication Code) combina un hash con una chiave segreta condivisa. L'hash semplice garantisce solo integrita' — chiunque puo' ricalcolare l'hash di un messaggio modificato. HMAC aggiunge autenticazione: solo chi conosce la shared key puo' produrre l'HMAC corretto. Senza la chiave, l'attaccante non puo' falsificare il codice anche se modifica il messaggio.

sequenceDiagram
    participant M as Mittente
    participant A as Attaccante MITM
    participant R as Ricevente

    Note over M,R: Condividono shared_key (scambiata in anticipo)

    M->>M: HMAC = SHA256(shared_key + messaggio)
    M->>A: messaggio + HMAC
    A->>A: Modifica il messaggio
    A->>A: Tenta di ricalcolare HMAC senza shared_key
    Note over A: IMPOSSIBILE senza la chiave
    A->>R: messaggio_modificato + HMAC_originale
    R->>R: Ricalcola SHA256(shared_key + messaggio_ricevuto)
    Note over R: HMAC calcolato != HMAC ricevuto
    Note over R: Manomissione rilevata

Lettura: Mittente e ricevente condividono la secret key. Il mittente calcola HMAC e lo invia con il messaggio. L'attaccante modifica il messaggio ma non riesce a produrre un HMAC valido senza la chiave. Il ricevente ricalcola l'HMAC sul messaggio ricevuto — il mismatch rivela la manomissione.

hash-attack-message-tampering.webp

Dev parallel: in PHP hash_hmac('sha256', $payload, $secret) e' esattamente quello che usi per verificare i webhook di Stripe o GitHub. Prima di processare un ordine ricevuto via webhook, calcoli l'HMAC del body con il secret che Stripe ti ha dato in dashboard — se corrisponde all'X-Stripe-Signature nell'header, il payload e' autentico. In Node.js e' crypto.createHmac('sha256', secret).update(payload).digest('hex'). Stesso concetto che usa TLS per ogni record (integrity check sul pacchetto dati) e IPsec per ogni pacchetto cifrato.


Password Hashing
#

Nessun sistema corretto salva la password in chiaro. Salva l'hash. Al login, ricalcola l'hash della password inserita e confronta. Il problema fondamentale e' che un hash veloce (MD5, SHA-1) diventa un vettore di attacco se il database viene compromesso.

graph LR
    PWD["password123"]
    SALT["salt casuale
    x7kQ9m"]
    BCRYPT["bcrypt
    cost=10
    2^10 iterazioni"]
    HASH["$2y$10$x7kQ9m...
    hash salvato nel DB"]
    CRACK["Attaccante
    ha il DB"]
    RT["Rainbow Table
    MD5 690 GB"]
    FAIL["FAIL
    salt rende la
    tabella inutile"]

    PWD --> BCRYPT
    SALT --> BCRYPT
    BCRYPT --> HASH
    CRACK -->|cerca| RT
    RT -->|ma| FAIL

Lettura: La password viene combinata con un salt casuale e processata da bcrypt (con 2^10 iterazioni). Il risultato — che include il salt — viene salvato nel DB. Un attaccante che ruba il DB e tenta di usare una rainbow table precalcolata fallisce: il salt rende l'hash unico per quell'utente, la tabella non serve.


Rainbow Tables e Salting
#

Una rainbow table e' un database precalcolato che mappa hash → password originale. Il costo computazionale viene pagato una volta sola da chi costruisce la tabella: poi ogni ricerca e' O(1), istantanea. Il salting e' la contromisura diretta: un valore casuale univoco aggiunto a ogni password prima dell'hash rende ogni entry nel DB impossibile da pre-calcolare.

Senza salt:
  hash("password123")           = 482c811...  (uguale per TUTTI gli utenti)
  → un'unica rainbow table colpisce TUTTI

Con salt univoco per ogni utente:
  hash("password123" + "x7kQ9m") = a93f2b1...  (utente Mario)
  hash("password123" + "p3mX2k") = f71c4e8...  (utente Luigi)
  → stessa password, hash completamente diversi
  → la rainbow table non serve: dovrebbe coprire ogni salt possibile
Warning

Il salt non e' un segreto e non serve tenerlo nascosto: va salvato nel DB perche' serve per ricalcolare l'hash al login. Il suo scopo e' solo rendere ogni hash unico — non aggiunge segreto, aggiunge randomness.


Key Stretching
#

Il salting neutralizza le rainbow tables ma non rallenta il brute force diretto. Su un dump del DB, Hashcat con GPU moderna processa miliardi di hash MD5/secondo. Il key stretching risolve questo: applica la funzione di hashing migliaia o milioni di volte (iterazioni), rendendo ogni singolo tentativo deliberatamente costoso.

Algoritmi a confronto:

AlgoritmoScopoVeloce?Sale?IterazioniUso tipico
MD5Checksum (NON sicurezza)Si' (deprecated)No1Legacy, da rimuovere
SHA-256Integrita' file, firmeSi'No1TLS, certificati, IOC
SHA-3Integrita', alternativa SHA-2Si'No1Standard NIST moderno
bcryptPassword storageNo (by design)Si' (embedded)2^costLinux, web app
PBKDF2Password + key derivationNo (by design)Si'Configurabile (1M+)WPA2, iOS, FIPS
Argon2idPassword storage modernoNo (by design)Si'+ memorySistemi nuovi

Dev parallel: ogni volta che chiami password_hash($password, PASSWORD_BCRYPT) in PHP o bcrypt.hash(password, 10) in Node.js, stai usando key stretching senza saperlo. L'algoritmo genera automaticamente un salt casuale, itera 2^10 volte, e restituisce una stringa con salt e hash gia' embedded: $2y$10$x7kQ9mNp.... Quando poi fai password_verify() o bcrypt.compare(), non ricostruisci la password in chiaro — ricalcoli lo stesso hash con lo stesso salt estratto automaticamente dall'output e confronti. Mai usare md5($password) o hash('sha256', $password) per le password: sono veloci per design, inutili contro Hashcat.

Tip

La detection di un attacco offline avviene PRIMA del cracking, non durante: il segnale e' l'esfiltrazione del DB (query anomala SELECT * FROM users nei log MySQL slow query, o traffico insolito verso l'esterno). Il cracking avviene su macchine dell'attaccante, senza toccare il tuo sistema. Monitorare l'exfiltration e' piu' efficace che monitorare i login.


Scenario Reale Blue Team
#

Hashing e HMAC sono presenti in ogni livello dello stack — dai log di autenticazione ai webhook alle configurazioni di rete.

# Calcola hash SHA-256 di un file (verifica integrita' prima di eseguire)
sha256sum software_download.tar.gz
# Confronta con il checksum pubblicato sul sito ufficiale

# Identifica algoritmo hash da un digest sconosciuto (per incident response)
# MD5:    128 bit = 32 char hex
# SHA-1:  160 bit = 40 char hex
# SHA-256: 256 bit = 64 char hex
echo -n "482c811da5d5b4bc6d497ffa98491e38" | wc -c  # 32 = MD5

# Verifica se un hash e' in un feed Threat Intelligence (IoC)
grep "482c811da5d5b4bc6d497ffa98491e38" /var/lib/suricata/rules/malware-hashes.txt

# Analizza costo hash bcrypt in un dump DB compromesso
# $2y$10$... → cost factor 10 → 2^10 = 1024 iterazioni
# $2y$12$... → cost factor 12 → 2^12 = 4096 iterazioni (piu' sicuro)
# Se vedi $1$ → MD5crypt (DEPRECATED, sostituire subito)
# Se vedi nessun $ e solo hex → hash in chiaro senza salt (CRITICO)

# Verifica HMAC di un webhook GitHub in bash
echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$GITHUB_SECRET"
# Confronta con X-Hub-Signature-256 nell'header della richiesta
Warning

Durante un incident response su un DB compromesso, se trovi hash in formato $apr1$ (MD5-APR, Apache) o $1$ (MD5crypt) — sono craccabili in ore. Se trovi hash esadecimali senza prefisso (MD5 puro) — sono craccabili in minuti. $2y$ (bcrypt) e' accettabile se il cost factor e' >= 10. Priorita' immediata: obbligare il reset delle password degli utenti colpiti.


Collegato a
#

  • crypto — categoria
  • cryptography — fondamentali crittografici: hashing, simmetrica, asimmetrica
  • asymmetric-encryption — firma digitale: si firma l'hash del documento, non il grezzo

Related