„Lo codifico in Base64 così nessuno può leggerlo.“ Questa frase compare in code review, messaggi Slack e risposte di Stack Overflow molto più di quanto dovrebbe. Base64 non è cifratura. Non è obfuscamento. Non è sicurezza di alcun tipo. Decodificarlo richiede una chiamata di funzione e zero conoscenza di una chiave o di un segreto. Questo articolo spiega cos'è davvero Base64, perché la confusione persiste e cosa usare al suo posto quando devi davvero proteggere dei dati.
Cos'è davvero Base64
Base64 è uno schema di codifica —— una mappatura reversibile tra dati binari e un insieme di 64 caratteri ASCII stampabili (A–Z, a–z, 0–9, +, /, con = come padding).
Ogni 3 byte di input diventano 4 caratteri Base64. L'algoritmo è completamente deterministico e non richiede chiavi:
// Codifica
btoa("hello") // → "aGVsbG8="
btoa("secret password") // → "c2VjcmV0IHBhc3N3b3Jk"
// Decodifica —— una chiamata, niente chiave
atob("c2VjcmV0IHBhc3N3b3Jk") // → "secret password"Tutto qui. Chiunque abbia accesso alla stringa codificata può decodificarla all'istante, in qualunque linguaggio, in qualunque ambiente, senza informazioni aggiuntive.
Perché esiste la confusione
Le stringhe codificate in Base64 sembrano dati cifrati. Sono piene di maiuscole, minuscole, numeri e caratteri speciali mescolati e non hanno alcuna somiglianza visibile con l'input originale. Questo rumore visivo basta a ingannare un osservatore non tecnico —— e, sorprendentemente, spesso anche uno tecnico.
Il pattern è rafforzato anche dalla vicinanza. Base64 compare di continuo in contesti di sicurezza:
- I certificati HTTPS sono codificati in Base64 (formato PEM)
- I token JWT usano la codifica Base64url per header e payload
- L'autenticazione HTTP Basic invia le credenziali come Base64
- Le chiavi SSH sono memorizzate come Base64
- I dati cifrati vengono spesso codificati in Base64 per il trasporto
Vedere Base64 in tutti questi posti adiacenti alla sicurezza porta gli sviluppatori a confondere codifica con sicurezza. La codifica è solo l'involucro; la sicurezza viene dalle operazioni crittografiche che ci sono sotto.
Codifica vs cifratura: la differenza centrale
La distinzione è semplice e assoluta:
| Codifica (Base64) | Cifratura (AES, RSA…) | |
|---|---|---|
| Scopo | Rappresentare dati binari come testo | Nascondere dati a parti non autorizzate |
| Richiede una chiave? | No | Sì |
| Reversibile da chiunque? | Sì —— una chiamata di funzione | Solo con la chiave giusta |
| Aggiunge riservatezza? | No | Sì (se usata correttamente) |
| Dimensione output | ~33% più grande dell'input | Varia in base all'algoritmo |
La cifratura trasforma i dati con una chiave in modo che, senza la chiave, recuperare l'originale sia computazionalmente non fattibile. La codifica Base64 non ha questa proprietà.
Errori di sicurezza nel mondo reale
Salvare segreti „codificati“ nel codice sorgente
// ❌ Questo non è segreto —— chiunque può decodificarlo
const API_KEY = atob("c2stbGl2ZS1hYmMxMjM0NTY3ODk=");
// Chiunque legga questo codice esegue:
atob("c2stbGl2ZS1hYmMxMjM0NTY3ODk=") // → "sk-live-abc123456789"Gli strumenti automatici di scansione dei segreti (GitHub Secret Scanning, GitGuardian, truffleHog) decodificano le stringhe Base64 come parte del rilevamento. Se conti sul Base64 per fermarli, non funzionerà.
Autenticazione HTTP Basic
// L'header Authorization è così:
Authorization: Basic dXNlcjpwYXNzd29yZA==
// Quel Base64 si decodifica in modo banale:
atob("dXNlcjpwYXNzd29yZA==") // → "user:password"L'autenticazione HTTP Basic è sicura solo su HTTPS —— il layer TLS fornisce la cifratura reale. Il Base64 nell'header serve puramente a codificare la coppia username:password come un singolo valore testuale, non a nasconderla. Su HTTP in chiaro, chiunque intercetti il traffico legge le credenziali all'istante.
Trattare i „token“ JWT come segreti
// Un JWT sembra tre sezioni Base64url unite da punti:
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQyfQ.abc123
// La sezione centrale (payload) si decodifica in:
atob("eyJ1c2VySWQiOjQyfQ") // → '{"userId":42}'I payload JWT non sono cifrati —— sono codificati in Base64url e firmati. Chiunque riceva il token può leggere il payload. La firma impedisce manomissioni ma non fornisce riservatezza. Non mettere mai dati sensibili (password, numeri di carta, informazioni personali) in un payload JWT a meno che tu non usi JWE (JSON Web Encryption), che è uno standard diverso e molto meno comune.
Offuscare dati nelle URL
// Pattern comune nelle app legacy
/profile?data=eyJ1c2VySWQiOjQyfQ==
// Incolla questo in qualunque decoder:
atob("eyJ1c2VySWQiOjQyfQ==") // → '{"userId":42}' Base64 nelle URL non aggiunge alcuna sicurezza. Si rompe anche facilmente —— i caratteri + e / del Base64 standard non sono URL-safe e vanno percent-encoded, motivo per cui Base64url (+ → -, / → _, senza padding) esiste come variante separata.
A cosa serve davvero Base64
Base64 ha usi legittimi e importanti —— solo non per la sicurezza:
- Incorporare dati binari in formati testo —— immagini, font e file incorporati come URI
data:in HTML/CSS o allegati in risposte JSON di API - Allegati email —— la codifica MIME usa Base64 per trasmettere file binari su protocolli che gestiscono solo ASCII a 7 bit
- Sicurezza di trasporto —— alcuni canali corrompono i dati binari (byte nulli, caratteri di controllo); Base64 garantisce che il contenuto sopravviva intatto
- Identificatori opachi —— codificare un ID o cursore come Base64 segnala ai consumer dell'API „non provare a parsare questo“, anche se non fornisce sicurezza
Cosa usare quando ti serve davvero sicurezza
Se l'obiettivo è prevenire l'accesso non autorizzato ai dati, usa uno strumento crittografico vero:
| Obiettivo | Cosa usare |
|---|---|
| Cifrare dati a riposo | AES-256-GCM (cifratura simmetrica) |
| Cifrare dati in transito | TLS 1.3 (HTTPS) |
| Hash di password | bcrypt, scrypt o Argon2 —— mai SHA-256 da solo |
| Firmare token | HMAC-SHA256 (come JWT HS256) o RS256 |
| Conservare segreti | Variabili d'ambiente, un secret manager (Vault, AWS Secrets Manager) |
| Cifrare token end-to-end | JWE (JSON Web Encryption) —— non JWT semplice |
Quando ti serve davvero un token cifrato: JWE e JOSE
Un JWT standard è firmato (JWS), non cifrato —— il payload è leggibile. Se ti serve davvero la riservatezza dei claim, usa un JWE (JSON Web Encryption, RFC 7516). JWE fa parte della famiglia di standard JOSE:
- Algoritmi JOSE —— cifratura del contenuto (es.
A256GCM) e gestione delle chiavi (es.RSA-OAEP-256,ECDH-ES,A256KW). „alg“ sceglie come viene avvolta la chiave di cifratura del contenuto; „enc“ sceglie come viene cifrato il payload. - Wrapping della chiave —— JWE genera una chiave di cifratura del contenuto nuova per messaggio e la avvolge sotto la chiave del destinatario (asimmetrica o simmetrica). La chiave avvolta viaggia nell'header del token. Questo permette di cifrare lo stesso testo in chiaro per destinatari diversi senza ricifrare il corpo.
- Forma compatta JWE —— cinque sezioni Base64url unite da punti (header.key.iv.ciphertext.tag), visivamente simile a un JWT ma con quattro pezzi invece di tre.
Scegli una libreria revisionata (jose, node-jose, python-jose) invece di implementare JWE per conto tuo —— le combinazioni di algoritmi e formati di chiave sono sottili, e il fallback silenzioso ad algoritmi deboli è un classico bug di JOSE.
Un test rapido per il tuo codice
Cerca nella tua codebase btoa(, atob( e Buffer.from(…, 'base64'). Per ogni occorrenza, chiediti:
- Lo faccio perché il testo stia in un campo o sopravviva al trasporto? → Bene.
- Lo faccio per nascondere dati a qualcuno? → Sostituiscilo con cifratura vera o controllo di accesso.
Domande frequenti
Base64 è cifratura?
No. Base64 è una codifica reversibile senza chiave —— chiunque può decodificarla in una chiamata (atob()). La cifratura richiede una chiave e rende non fattibile recuperare il contenuto senza di essa.
È sicuro salvare password o chiavi API in Base64?
No. La decodifica è banale e gli scanner di segreti decodificano Base64 automaticamente. Usa un secret manager o variabili d'ambiente e fai l'hash delle password con bcrypt, scrypt o Argon2.
Chiunque può leggere il payload di un JWT?
Sì. I payload JWT sono codificati in Base64url e firmati, non cifrati —— chiunque abbia il token può leggere tutti i claim. Non mettere mai segreti in un JWT a meno di non usare JWE. Incollare token in strumenti online è rischioso; vedi perché non dovresti incollare JSON sensibile online.
A cosa serve allora Base64?
Rappresentare dati binari come testo in modo sicuro —— URI data:, allegati email (MIME) e trasporto su canali che gestiscono solo ASCII. È un involucro, non una misura di sicurezza.
Codifica e decodifica nel browser
Devi ispezionare una stringa Base64 ora? Codifica e decodifica Base64 su fixjson.org ti permette di codificare o decodificare qualunque stringa all'istante —— incluso Unicode completo e UTF-8 —— senza installare nulla. Utile per debug di payload JWT, ispezionare risposte API o vedere cosa si nasconde dentro un URI data:.
- Codifica e decodifica Base64 —— all'istante, nel browser, nessun dato inviato a un server
- RFC 4648: lo standard Base64 —— la storia e la definizione formale di Base64 e Base64url
- Come decodificare un JWT —— leggere i claim di un token e perché decodificare non è verificare
- RFC 7519: JSON Web Token (JWT) —— come Base64url è usato nello standard JWT e considerazioni di sicurezza
- Decode URL —— decodifica percent-encoding di una URL o query string
- JSON Stringify —— codifica un valore JSON come literal di stringa escaped