In ogni progetto .NET, prima o poi si ha bisogno di decodificare Base64 — estrarre stringhe di connessione da Kubernetes secrets, leggere payload binari da webhook, o ispezionare token JWT durante una sessione di debug. Per decodificare Base64 in C#, il metodo principale è Convert.FromBase64String(), che restituisce un byte[] da passare poi a Encoding.UTF8.GetString() per ottenere testo leggibile. Per una verifica rapida senza scrivere codice, il decoder Base64 di ToolDeck lo gestisce istantaneamente nel browser. Questa guida copre Convert.FromBase64String(), il metodo basato su span TryFromBase64String()per .NET 5+, l'API ad alte prestazioni System.Buffers.Text.Base64, l'estrazione del payload JWT, la decodifica di file e risposte API, lo streaming con CryptoStream, e i quattro errori più frequenti tra gli sviluppatori C#.
- ✓Convert.FromBase64String(s) + Encoding.UTF8.GetString(bytes) è la pipeline standard in due passi — funziona su tutte le versioni di .NET.
- ✓Convert.TryFromBase64String() evita le eccezioni su input non valido e scrive in uno Span<byte> — ideale per i percorsi critici su .NET 5+.
- ✓System.Buffers.Text.Base64.DecodeFromUtf8() offre decodifica senza allocazioni per buffer di byte UTF-8 in servizi ad alte prestazioni.
- ✓I token JWT usano Base64url (- e _ al posto di + e /) — devi normalizzare l'input prima di chiamare Convert.FromBase64String().
- ✓CryptoStream con FromBase64Transform gestisce la decodifica in streaming per file di grandi dimensioni senza caricare tutto in memoria.
Cos'è la decodifica Base64?
La codifica Base64 converte dati binari in un alfabeto ASCII di 64 caratteri in modo che sopravvivano al trasporto su canali solo testo — campi JSON, header HTTP, corpi email, attributi XML. Ogni 3 byte di input diventano 4 caratteri Base64, motivo per cui l'output Base64 è sempre circa il 33% più grande dell'originale. La decodifica inverte questa trasformazione. Il padding =finale indica al decoder quanti byte rimuovere dall'ultimo gruppo. Un singolo =significa che l'ultimo blocco aveva 2 byte; == significa che ne aveva 1. Base64 non è crittografia — chiunque può invertirla. Lo scopo è il trasporto sicuro attraverso canali che modificano i dati binari grezzi, non la riservatezza.
cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ==
redis://cache-prod.internal:6379/session-store
Convert.FromBase64String() — Il metodo di decodifica standard
Il metodo Convert.FromBase64String() è presente in .NET sin dai giorni del Framework 1.1. Nessun pacchetto NuGet, nessun import aggiuntivo oltre a System — basta chiamarlo e ottenere un byte[]. La pipeline in due passi per decodificare Base64 in una stringa C# è sempre la stessa: Convert.FromBase64String() per ottenere i byte, poi Encoding.UTF8.GetString() per interpretarli come testo. Il problema è che il metodo restituisce byte grezzi, non una stringa. Devi scegliere la Encoding giusta per riconvertire quei byte in testo, e la scelta è più importante di quanto la maggior parte delle persone si aspetti. Una codifica errata produce silenziosamente mojibake — caratteri corrotti senza alcuna eccezione di avviso.
Esempio minimo funzionante
using System; using System.Text; // Stringa di connessione memorizzata come Base64 in un Kubernetes secret string encoded = "cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ=="; byte[] decodedBytes = Convert.FromBase64String(encoded); string connectionString = Encoding.UTF8.GetString(decodedBytes); Console.WriteLine(connectionString); // redis://cache-prod.internal:6379/session-store
Usa sempre Encoding.UTF8 a meno che non ci sia un motivo specifico per non farlo. Il runtime .NET rappresenta le stringhe internamente come UTF-16, ma la maggior parte dei dati che attraversano i confini di sistema (risposte API, file di configurazione, secrets) è codificata in UTF-8. Usare Encoding.ASCII su dati che contengono caratteri multi-byte li sostituisce silenziosamente con ? — nessuna eccezione, solo output corrotto.
Verifica del round-trip
using System; using System.Text; string original = "postgres://db-admin:Kx8!mQ@db-prod.us-east-1.internal:5432/orders"; // Codifica string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(original)); Console.WriteLine(encoded); // cG9zdGdyZXM6Ly9kYi1hZG1pbjpLeDghbVFAZGItcHJvZC51cy1lYXN0LTEuaW50ZXJuYWw6NTQzMi9vcmRlcnM= // Decodifica byte[] decoded = Convert.FromBase64String(encoded); string recovered = Encoding.UTF8.GetString(decoded); Console.WriteLine(recovered == original); // True
Scegliere la codifica giusta
La Encoding passata a GetString() deve corrispondere a quella usata quando i dati sono stati codificati originariamente. Sbagliare produce caratteri incomprensibili senza alcuna eccezione — il decoder produce tranquillamente spazzatura. Ecco la guida pratica:
Encoding.UTF8— valore predefinito sicuro. Gestisce ASCII e tutto Unicode. Usalo a meno che tu non sappia altrimenti.Encoding.ASCII— solo per dati ASCII puri a 7 bit. I caratteri multi-byte diventano?.Encoding.Unicode— questo è UTF-16LE in .NET. Alcune stringhe interne a Windows ed esportazioni PowerShell lo usano.Encoding.Latin1— codifica Western European legacy. Compare nei vecchi servizi SOAP e nelle integrazioni con mainframe.
using System;
using System.Text;
// Stessi byte, codifiche diverse — risultati diversi
byte[] decoded = Convert.FromBase64String("w7bDvMOk");
Console.WriteLine(Encoding.UTF8.GetString(decoded)); // öüä (corretto)
Console.WriteLine(Encoding.ASCII.GetString(decoded)); // ?????? (perso)
Console.WriteLine(Encoding.Latin1.GetString(decoded)); // öüä (mojibake)Un helper di decodifica riutilizzabile con gestione degli errori
Poiché Convert.FromBase64String()lancia eccezioni su input non valido e la rimozione degli spazi bianchi è un'operazione ricorrente, tengo un piccolo helper nella maggior parte dei progetti:
using System;
using System.Text;
static class Base64Helper
{
public static string? DecodeToString(string encoded)
{
if (string.IsNullOrWhiteSpace(encoded))
return null;
// Rimuovi gli spazi bianchi che il decoder di .NET rifiuta
string cleaned = encoded
.Replace("
", "")
.Replace("
", "")
.Replace(" ", "")
.Trim();
try
{
byte[] bytes = Convert.FromBase64String(cleaned);
return Encoding.UTF8.GetString(bytes);
}
catch (FormatException)
{
return null; // o lancia un'eccezione specifica del dominio
}
}
}
// Utilizzo
string? decoded = Base64Helper.DecodeToString(" cmVkaXM6Ly9jYWNoZQ== \n");
Console.WriteLine(decoded); // redis://cacheConvert.FromBase64String() lancia FormatExceptionse l'input contiene caratteri al di fuori dell'alfabeto Base64 — compresi spazi, newline e caratteri URL-safe come - e _. L'helper sopra gestisce automaticamente gli spazi bianchi.Decodifica Base64 in tipi non standard
Il decoder restituisce sempre un byte[]. Cosa fai con quei byte dipende dai dati originali. A volte è un GUID memorizzato come 16 byte grezzi, a volte è un messaggio protobuf serializzato, a volte è un timestamp in formato binario. Ecco le conversioni che uso più spesso.
Base64 in GUID
using System; // Alcune API inviano GUID come Base64 a 22 caratteri invece di stringhe hex a 36 caratteri string compactGuid = "C0HqetxMckKlZw4CssPUeQ=="; byte[] guidBytes = Convert.FromBase64String(compactGuid); Guid recovered = new Guid(guidBytes); Console.WriteLine(recovered); // 7aea41c0-4cdc-4272-a567-0e02b2c3d479
Base64 in JSON deserializzato con System.Text.Json
using System;
using System.Text;
using System.Text.Json;
// Payload JSON codificato in Base64 da una coda di messaggi
string encoded = "eyJzZXJ2aWNlIjoicGF5bWVudC1nYXRld2F5IiwicmVnaW9uIjoiZXUtd2VzdC0xIiwicmVwbGljYXMiOjR9";
byte[] jsonBytes = Convert.FromBase64String(encoded);
string json = Encoding.UTF8.GetString(jsonBytes);
Console.WriteLine(json);
// {"service":"payment-gateway","region":"eu-west-1","replicas":4}
// Deserializza in un record
var deployEvent = JsonSerializer.Deserialize<DeployEvent>(jsonBytes);
Console.WriteLine($"{deployEvent!.Service} in {deployEvent.Region}");
// payment-gateway in eu-west-1
record DeployEvent(string Service, string Region, int Replicas);Base64 in stringa esadecimale
using System; // Hash SHA-256 memorizzato come Base64 string hashBase64 = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="; byte[] hashBytes = Convert.FromBase64String(hashBase64); string hex = Convert.ToHexString(hashBytes); Console.WriteLine(hex); // 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08
BinaryFormatter. Ha vulnerabilità note di esecuzione remota di codice ed è obsoleto in .NET 8+. Se il contenuto codificato proviene da una fonte esterna, analizzalo come JSON o protobuf invece di usare la serializzazione binaria di .NET.Riferimento ai metodi di decodifica Base64
.NET fornisce più metodi di decodifica distribuiti in due namespace. La classe Convert gestisce la decodifica di uso generale, mentre System.Buffers.Text.Base64 è orientato agli scenari ad alto throughput dove si lavora già con buffer di byte UTF-8 grezzi.
Convert.TryFromBase64String() — Decodifica senza eccezioni
Il pattern Tryè standard in .NET per le operazioni che potrebbero fallire sull'input dell'utente. Convert.TryFromBase64String(), disponibile da .NET 5, restituisce un bool invece di lanciare FormatException. Scrive i byte decodificati in uno Span<byte>fornito dal chiamante, il che significa che puoi usare memoria allocata sullo stack per payload piccoli ed evitare completamente l'heap.
using System;
using System.Text;
string userInput = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=";
// Alloca sullo stack per payload piccoli (< 1 KB è una regola pratica sicura)
Span<byte> buffer = stackalloc byte[256];
if (Convert.TryFromBase64String(userInput, buffer, out int bytesWritten))
{
string result = Encoding.UTF8.GetString(buffer[..bytesWritten]);
Console.WriteLine(result);
// {"host":"10.0.1.50","port":8443}
}
else
{
Console.WriteLine("Input Base64 non valido — saltato");
}Questo approccio è particolarmente efficace nei middleware di richiesta o nelle pipeline di validazione dove l'input non valido è atteso, non eccezionale. Lanciare e catturare una FormatException per ogni richiesta malformata aggiunge un overhead misurabile su larga scala — TryFromBase64String() lo evita completamente.
Validare l'input Base64 senza decodificarlo
Un pattern comune nei controller API: verificare se l'input è Base64 valido prima di passarlo a valle. Puoi usare TryFromBase64String() come validatore allocando un buffer usa-e-getta:
using System;
static bool IsValidBase64(string input)
{
// Calcola la dimensione massima decodificata
Span<byte> buffer = stackalloc byte[((input.Length + 3) / 4) * 3];
return Convert.TryFromBase64String(input, buffer, out _);
}
// Utilizzo in un controller API
Console.WriteLine(IsValidBase64("eyJob3N0IjoiMTAuMC4xLjUwIn0=")); // True
Console.WriteLine(IsValidBase64("not!!valid!!base64")); // False
Console.WriteLine(IsValidBase64("")); // True (vuoto è valido)TryFromBase64String() restituisce falseanche quando l'input è valido. Calcola la dimensione richiesta come (inputLength / 4) * 3 per stare al sicuro.Decodifica Base64 da file e risposte API
Lettura di un file codificato in Base64 dal disco
Certificati, blob cifrati e file di esportazione dati sono talvolta distribuiti come testo Base64. Il pattern tipico: leggi il file come stringa, rimuovi eventuali spazi o interruzioni di riga che causerebbero FormatException, decodifica in byte e scrivi l'output binario. Presta attenzione alla gestione degli errori — gli errori di I/O su file e gli errori di formato Base64 devono essere catturati separatamente.
using System;
using System.IO;
string inputPath = "tls-cert.pem.b64";
string outputPath = "tls-cert.pem";
try
{
string encoded = File.ReadAllText(inputPath).Trim();
// Rimuovi le interruzioni di riga — il decoder di .NET le rifiuta
encoded = encoded.Replace("
", "").Replace("
", "");
byte[] decoded = Convert.FromBase64String(encoded);
File.WriteAllBytes(outputPath, decoded);
Console.WriteLine($"Decoded {decoded.Length} bytes -> {outputPath}");
}
catch (IOException ex)
{
Console.Error.WriteLine($"File error: {ex.Message}");
}
catch (FormatException ex)
{
Console.Error.WriteLine($"Invalid Base64: {ex.Message}");
}Decodifica di un campo Base64 da una risposta API HTTP
Le API cloud (Azure Key Vault, AWS Secrets Manager, GitHub Contents API) restituiscono spesso dati binari come stringhe Base64 incorporate nel JSON. Il flusso di lavoro è sempre lo stesso: effettua la richiesta HTTP, analizza la risposta JSON, estrai il campo Base64 e decodificalo. L'esempio seguente usa HttpClient e System.Text.Json — entrambi integrati in .NET 6+.
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk-prod-9f8e7d6c");
try
{
var response = await client.GetAsync("https://api.example.com/secrets/db-password");
response.EnsureSuccessStatusCode();
string body = await response.Content.ReadAsStringAsync();
// API restituisce: {"name":"db-password","value":"cG9zdGdyZXM6eGs5bVAycVI=","version":3}
using var doc = JsonDocument.Parse(body);
string encodedValue = doc.RootElement.GetProperty("value").GetString()!;
byte[] decoded = Convert.FromBase64String(encodedValue);
string secret = Encoding.UTF8.GetString(decoded);
Console.WriteLine($"Secret: {secret}");
// Secret: postgres:xk9mP2qR
}
catch (HttpRequestException ex)
{
Console.Error.WriteLine($"HTTP error: {ex.Message}");
}
catch (FormatException ex)
{
Console.Error.WriteLine($"Base64 decode failed: {ex.Message}");
}catch per gli errori di rete e FormatException. Raggrupparli insieme rende difficile capire se l'API ha restituito dati errati o se la richiesta stessa è fallita. In produzione, registra il valore Base64 grezzo (o almeno la sua lunghezza e i primi 20 caratteri) quando catturi FormatException — rende il debug molto più semplice.Decodifica Base64 dalla riga di comando
Non sempre è necessario un progetto compilato. Lo strumento dotnet-script e PowerShell gestiscono entrambi la decodifica Base64 con una sola riga. Per una rapida ispezione durante il debug, sono più veloci della creazione di un'applicazione console.
# PowerShell (integrato in Windows, disponibile su Linux/macOS)
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("eyJob3N0IjoiMTAuMC4xLjUwIn0="))
# {"host":"10.0.1.50"}
# Comando base64 nativo su Linux / macOS
echo "eyJob3N0IjoiMTAuMC4xLjUwIn0=" | base64 --decode
# {"host":"10.0.1.50"}
# macOS usa -D invece di --decode
echo "eyJob3N0IjoiMTAuMC4xLjUwIn0=" | base64 -D
# dotnet-script (installa con: dotnet tool install -g dotnet-script)
echo 'Console.WriteLine(System.Text.Encoding.UTF8.GetString(Convert.FromBase64String("eyJob3N0IjoiMTAuMC4xLjUwIn0=")));' | dotnet-script eval
# Decodifica e formatta JSON con jq
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode | jq .Per incollare stringhe codificate direttamente nel browser, il decoder Base64 online di ToolDeck gestisce sia le varianti standard che URL-safe senza alcuna configurazione.
Alternativa ad alte prestazioni: System.Buffers.Text.Base64
La classe System.Buffers.Text.Base64, disponibile da .NET Core 2.1, opera su span di byte UTF-8 grezzi invece di stringhe .NET. Questo bypassa completamente il costo della conversione stringa-byte — nessuna allocazione di stringa intermedia, nessun passaggio di codifica UTF-16. La utilizzo nel middleware ASP.NET Core dove i dati in arrivo sono già un ReadOnlySpan<byte> dal corpo della richiesta. Creare una string solo per passarla a Convert.FromBase64String() raddoppia le allocazioni senza motivo. Nei test BenchmarkDotNet su .NET 8, il percorso basato su span è circa 2-3 volte più veloce per payload inferiori a 1 KB e il divario si amplia con input più grandi perché la pressione sul GC rimane costante.
using System;
using System.Buffers.Text;
using System.Text;
// Simula byte UTF-8 grezzi dal corpo di una richiesta HTTP
byte[] utf8Input = Encoding.UTF8.GetBytes("eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=");
byte[] output = new byte[Base64.GetMaxDecodedFromUtf8Length(utf8Input.Length)];
OperationStatus status = Base64.DecodeFromUtf8(
utf8Input, output, out int bytesConsumed, out int bytesWritten);
if (status == OperationStatus.Done)
{
string result = Encoding.UTF8.GetString(output.AsSpan(0, bytesWritten));
Console.WriteLine(result);
// {"host":"10.0.1.50","port":8443}
Console.WriteLine($"Consumed: {bytesConsumed}, Written: {bytesWritten}");
// Consumed: 44, Written: 31
}
else
{
Console.WriteLine($"Decode failed: {status}");
// Possibili: InvalidData, DestinationTooSmall, NeedMoreData
}Il tipo restituito è OperationStatus — un enum con quattro valori: Done, InvalidData, DestinationTooSmall, e NeedMoreData. L'ultimo è utile per la decodifica parziale di dati in streaming. Per zero allocazioni assolute, abbina questo con ArrayPool<byte>.Shared.Rent() invece di new byte[].
DecodeFromUtf8InPlace — sovrascrivere il buffer di input
using System;
using System.Buffers.Text;
using System.Text;
// Il buffer di input viene sovrascritto con i byte decodificati
byte[] data = Encoding.UTF8.GetBytes("c2VydmVyLWNvbmZpZw==");
OperationStatus status = Base64.DecodeFromUtf8InPlace(data, out int bytesWritten);
if (status == OperationStatus.Done)
{
Console.WriteLine(Encoding.UTF8.GetString(data.AsSpan(0, bytesWritten)));
// server-config
}DecodeFromUtf8InPlace modifica il buffer di input. Non usarlo se hai bisogno della stringa Base64 originale in seguito — i primi bytesWritten byte dell'array ora contengono i dati decodificati, il resto è spazzatura.Una cosa da tenere a mente: System.Buffers.Text.Base64non gestisce Base64 URL-safe direttamente. Se l'input usa i caratteri - e _ (token JWT, per esempio), devi comunque sostituirli con + e /prima di chiamare questi metodi. Le API basate su span seguono strettamente l'alfabeto standard RFC 4648. Non esiste una variante DecodeFromUtf8Url — una lacuna sorprendente data la diffusione di Base64url nelle API moderne.
Output terminale con syntax highlighting
La libreria Spectre.Consoleoffre output terminale ricco incluso l'highlighting JSON — utile quando si costruiscono strumenti CLI che decodificano Base64 e mostrano il risultato. Installala con dotnet add package Spectre.Console.
using System;
using System.Text;
using Spectre.Console;
using Spectre.Console.Json;
string encoded = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0MywibWF4Q29ubiI6MTAwfQ==";
byte[] decoded = Convert.FromBase64String(encoded);
string json = Encoding.UTF8.GetString(decoded);
// Stampa formattata con syntax highlighting nel terminale
AnsiConsole.Write(new JsonText(json));
// Output JSON colorato:
// {
// "host": "10.0.1.50",
// "port": 8443,
// "maxConn": 100
// }Questo è particolarmente utile per strumenti CLI che recuperano e decodificano configurazioni da servizi remoti. Decodifica la configurazione Base64, deserializza in JSON e stampa l'output con highlighting — tutto in poche righe. Spectre.Console ha anche rendering di tabelle, barre di avanzamento e viste ad albero se hai bisogno di visualizzare strutture dati decodificate più complesse nel terminale.
Streaming di file Base64 di grandi dimensioni con CryptoStream
Caricare un file Base64 da 500 MB con File.ReadAllText() e poi chiamare Convert.FromBase64String()alloca circa 700 MB di heap: la stringa stessa (UTF-16, quindi il doppio della dimensione del file) più l'array di byte decodificati. La combinazione CryptoStream + FromBase64Transform decodifica a blocchi, mantenendo costante l'utilizzo della memoria.
using System.IO;
using System.Security.Cryptography;
string inputPath = "database-export.sql.b64";
string outputPath = "database-export.sql";
using var inputStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
using var transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces);
using var base64Stream = new CryptoStream(inputStream, transform, CryptoStreamMode.Read);
using var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write);
base64Stream.CopyTo(outputStream);
Console.WriteLine($"Decoded {new FileInfo(outputPath).Length} bytes -> {outputPath}");Il flag FromBase64TransformMode.IgnoreWhiteSpacesgestisce il Base64 con a capo (file PEM, esportazioni email) senza pulizia manuale. Senza questo flag, le interruzioni di riga nell'input causano una FormatException. Questo è l'equivalente più vicino in .NET a getMimeDecoder() di Java — ignora silenziosamente i caratteri di spazio durante la decodifica.
Il nome CryptoStreamè fuorviante — non c'è nulla di crittografico nel Base64. Microsoft ha inserito FromBase64Transform nel namespace System.Security.Cryptography perché implementa ICryptoTransform, la stessa interfaccia usata per AES e altre trasformazioni cipher. Lo stream stesso passa semplicemente i dati attraverso qualsiasi trasformazione a blocchi. Pensalo come una pipeline di trasformazione in streaming di uso generale che si trova nel namespace sbagliato.
Streaming asincrono per scenari ASP.NET Core
using System.IO;
using System.Security.Cryptography;
async Task DecodeStreamAsync(Stream inputStream, string outputPath)
{
using var transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces);
using var base64Stream = new CryptoStream(inputStream, transform, CryptoStreamMode.Read);
await using var outputStream = new FileStream(
outputPath, FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 81920, useAsync: true);
await base64Stream.CopyToAsync(outputStream);
}
// Utilizzo in un endpoint:
// await DecodeStreamAsync(Request.Body, "uploaded-file.bin");CopyTo a CopyToAsyncnei gestori ASP.NET Core. L'I/O sincrono sul thread della richiesta è bloccato per impostazione predefinita in Kestrel e lancia una InvalidOperationException.Come decodificare il payload di un token JWT Base64 in C#
Un JWT ha tre segmenti codificati in Base64url separati da punti. Il segmento centrale è il payload. Puoi decodificarlo senza ricorrere a una libreria JWT — dividi su ., normalizza i caratteri Base64url, correggi il padding, e chiama Convert.FromBase64String(). Questo causa problemi a quasi tutti la prima volta perché JWT usa - e _ al posto di + e /, e omette il padding =.
using System;
using System.Text;
static string DecodeJwtPayload(string token)
{
string[] parts = token.Split('.');
if (parts.Length != 3)
throw new ArgumentException($"Invalid JWT: expected 3 segments, got {parts.Length}");
// Prendi il payload (secondo segmento)
string payload = parts[1];
// Sostituisci i caratteri URL-safe con Base64 standard
payload = payload.Replace('-', '+').Replace('_', '/');
// Aggiungi il padding a un multiplo di 4
switch (payload.Length % 4)
{
case 2: payload += "=="; break;
case 3: payload += "="; break;
}
byte[] bytes = Convert.FromBase64String(payload);
return Encoding.UTF8.GetString(bytes);
}
// Test con un token dalla forma reale
string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
+ ".eyJzdWIiOiJ1c3ItNjcyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIsImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJiaWxsaW5nIl19"
+ ".SIGNATURE_PLACEHOLDER";
Console.WriteLine(DecodeJwtPayload(token));
// {"sub":"usr-672","iss":"auth.example.com","exp":1741956800,"roles":["admin","billing"]}Nota rapida: questo legge solo il payload. Nonverifica la firma. Per la validazione dell'autenticazione in produzione, usa una libreria appropriata come Microsoft.IdentityModel.JsonWebTokens. Ma per il debug, il logging e le asserzioni di test, questo approccio manuale è tutto ciò di cui hai bisogno.
Analisi del payload JWT decodificato in un oggetto tipizzato
Una volta ottenuta la stringa JSON, deserializzala con System.Text.Json per accedere ai singoli claim senza manipolazione di stringhe:
using System;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
record JwtPayload(
[property: JsonPropertyName("sub")] string Subject,
[property: JsonPropertyName("iss")] string Issuer,
[property: JsonPropertyName("exp")] long Expiration,
[property: JsonPropertyName("roles")] string[] Roles
);
// Dopo DecodeJwtPayload() dall'esempio sopra
string json = DecodeJwtPayload(token);
var claims = JsonSerializer.Deserialize<JwtPayload>(json)!;
Console.WriteLine($"User: {claims.Subject}");
Console.WriteLine($"Issuer: {claims.Issuer}");
Console.WriteLine($"Expires: {DateTimeOffset.FromUnixTimeSeconds(claims.Expiration):u}");
Console.WriteLine($"Roles: {string.Join(", ", claims.Roles)}");
// User: usr-672
// Issuer: auth.example.com
// Expires: 2025-03-14 12:00:00Z
// Roles: admin, billingErrori comuni
Ho incontrato ognuno di questi in servizi C# in produzione. I primi due sono responsabili della maggior parte dei bug legati a Base64 che vedo nelle code review. Ogni errore sembra ovvio in isolamento, ma è facile perdersi quando sei immerso in una funzionalità più grande e la decodifica Base64 è solo un passaggio nella pipeline.
Problema: Le stringhe Base64 lette da file di configurazione, variabili d'ambiente o input dell'utente spesso hanno newline finali. Convert.FromBase64String() rifiuta qualsiasi carattere al di fuori dell'alfabeto Base64, compresi \r\n.
Soluzione: Chiama .Trim() o .Replace() per rimuovere gli spazi bianchi prima della decodifica.
// La variabile d'ambiente ha un newline finale
string encoded = Environment.GetEnvironmentVariable("DB_PASS_B64")!;
byte[] decoded = Convert.FromBase64String(encoded);
// FormatException: The input is not a valid Base-64 stringstring encoded = Environment.GetEnvironmentVariable("DB_PASS_B64")!;
string cleaned = encoded.Replace("\n", "").Replace("\r", "").Trim();
byte[] decoded = Convert.FromBase64String(cleaned);
Console.WriteLine(Encoding.UTF8.GetString(decoded));Problema: I token JWT e alcuni payload API usano - e _ (alfabeto URL-safe). Il decoder standard accetta solo + e / — lancia FormatException al primo carattere -.
Soluzione: Sostituisci - con + e _ con / prima della decodifica. Correggi anche il padding.
// Payload JWT — usa Base64 URL-safe string payload = "eyJzdWIiOiJ1c3ItNjcyIn0"; byte[] decoded = Convert.FromBase64String(payload); // FormatException
string payload = "eyJzdWIiOiJ1c3ItNjcyIn0";
payload = payload.Replace('-', '+').Replace('_', '/');
switch (payload.Length % 4)
{
case 2: payload += "=="; break;
case 3: payload += "="; break;
}
byte[] decoded = Convert.FromBase64String(payload);
Console.WriteLine(Encoding.UTF8.GetString(decoded));
// {"sub":"usr-672"}Problema: Chiamare Encoding.UTF8.GetString() su byte di immagine o protobuf decodificati produce spazzatura. Peggio ancora, riconvertire quella stringa in byte corrompe silenziosamente i dati perché le sequenze UTF-8 non valide vengono sostituite.
Soluzione: Mantieni i dati binari come byte[] in tutta la pipeline. Chiama GetString() solo quando sai che il contenuto è testo.
byte[] decoded = Convert.FromBase64String(pngBase64);
string imageStr = Encoding.UTF8.GetString(decoded); // corrompe i dati binari
File.WriteAllText("image.png", imageStr); // file danneggiatobyte[] decoded = Convert.FromBase64String(pngBase64);
// Scrivi i byte direttamente — nessuna conversione in stringa
File.WriteAllBytes("image.png", decoded);Problema: Alcune API .NET Framework più vecchie usano come predefinita la code page ANSI corrente del sistema, che varia tra le macchine. Un server Windows con code page 1252 e un container Linux con UTF-8 producono stringhe diverse dagli stessi byte.
Soluzione: Specifica sempre Encoding.UTF8 esplicitamente. Non fare mai affidamento sul predefinito della piattaforma.
byte[] decoded = Convert.FromBase64String(encoded); // Encoding.Default varia tra le piattaforme string result = Encoding.Default.GetString(decoded);
byte[] decoded = Convert.FromBase64String(encoded); string result = Encoding.UTF8.GetString(decoded); // consistente su Windows, Linux, macOS
Confronto tra metodi
.NET offre più metodi di decodifica Base64 di quanto la maggior parte degli sviluppatori si renda conto. La tabella seguente copre ogni opzione integrata più le due alternative di terze parti più comuni. La colonna "Allocazione" è quella che conta di più nei servizi ad alto throughput — un metodo che alloca un nuovo byte[] ad ogni chiamata esercita pressione sul GC nei cicli stretti.
Per il lavoro quotidiano: Convert.FromBase64String(). Per i percorsi critici dove si valida l'input dell'utente: TryFromBase64String(). Per il middleware ASP.NET Core che opera su byte grezzi della richiesta: Base64.DecodeFromUtf8(). Per file di grandi dimensioni: CryptoStream + FromBase64Transform. BouncyCastle ha senso solo se è già nel tuo albero delle dipendenze per altre operazioni crittografiche.
Per una verifica rapida senza compilare nulla, il decoder Base64 online è più veloce dello scrivere un'applicazione console usa-e-getta.
Domande frequenti
Come si decodifica una stringa Base64 in testo in C#?
Chiama Convert.FromBase64String() per ottenere un array di byte, poi passalo a Encoding.UTF8.GetString(). La codifica deve corrispondere a quella usata durante la codifica — UTF-8 è il valore predefinito sicuro per quasi tutti i sistemi moderni. Se l'input potrebbe contenere spazi o interruzioni di riga, chiama .Trim() o rimuovili prima della decodifica.
using System; using System.Text; string encoded = "cG9zdGdyZXM6eGs5bVAycVI="; byte[] bytes = Convert.FromBase64String(encoded); string result = Encoding.UTF8.GetString(bytes); Console.WriteLine(result); // postgres:xk9mP2qR
Qual è la differenza tra Convert.FromBase64String() e Convert.TryFromBase64String()?
FromBase64String() lancia una FormatException in caso di input non valido. TryFromBase64String() restituisce un bool e scrive il risultato in uno Span<byte> fornito dal chiamante, rendendolo adatto ai percorsi critici dove si vuole evitare il costo delle eccezioni. TryFromBase64String() richiede .NET 5 o versioni successive.
using System;
string input = "maybe-not-valid-base64!!";
Span<byte> buffer = stackalloc byte[256];
if (Convert.TryFromBase64String(input, buffer, out int written))
Console.WriteLine($"Decoded {written} bytes");
else
Console.WriteLine("Invalid Base64 input");Come si decodifica un payload JWT Base64url in C#?
Dividi il token sui punti, prendi il secondo segmento, sostituisci - con + e _ con /, aggiungi il padding a un multiplo di 4 con =, poi chiama Convert.FromBase64String(). I token JWT usano l'alfabeto Base64 URL-safe, che il decoder standard di .NET non gestisce direttamente.
string token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3ItNjcyIn0.SIG";
string payload = token.Split('.')[1];
payload = payload.Replace('-', '+').Replace('_', '/');
switch (payload.Length % 4)
{
case 2: payload += "=="; break;
case 3: payload += "="; break;
}
byte[] bytes = Convert.FromBase64String(payload);
Console.WriteLine(Encoding.UTF8.GetString(bytes));
// {"sub":"usr-672"}Come si sceglie la codifica giusta per decodificare Base64 in C#?
Usa Encoding.UTF8 come predefinito — gestisce ASCII e caratteri Unicode multi-byte. Usa Encoding.ASCII solo quando sei certo che i dati siano ASCII puro a 7 bit. Usa Encoding.Unicode (che è UTF-16LE in .NET) solo quando i dati originali erano codificati come UTF-16, il che accade talvolta con stringhe interne a Windows ed esportazioni PowerShell.
Perché Convert.FromBase64String() lancia FormatException?
Tre cause comuni: l'input contiene spazi o interruzioni di riga (rimuovili prima della decodifica), l'input usa caratteri URL-safe come - e _ (sostituiscili rispettivamente con + e /), oppure il padding è mancante o errato (la lunghezza totale deve essere un multiplo di 4 dopo il padding). A differenza di Java, .NET non ha un decoder MIME integrato che tollera gli spazi — devi pulire l'input da solo o usare CryptoStream con FromBase64Transform in modalità IgnoreWhiteSpaces.
// Rimuovi gli spazi bianchi
string cleaned = rawInput.Replace("\n", "").Replace("\r", "").Trim();
byte[] decoded = Convert.FromBase64String(cleaned);Posso decodificare in streaming grandi quantità di dati Base64 in C#?
Sì. Usa un CryptoStream con FromBase64Transform da System.Security.Cryptography. Questo decodifica a blocchi mentre leggi, quindi l'utilizzo della memoria rimane costante indipendentemente dalla dimensione del file. Passa FromBase64TransformMode.IgnoreWhiteSpaces se l'input contiene interruzioni di riga. Su .NET 6+, puoi anche usare il pattern IAsyncEnumerable con Base64.DecodeFromUtf8() per l'elaborazione manuale a blocchi, anche se CryptoStream è più semplice per la decodifica da file a file.
using System.IO;
using System.Security.Cryptography;
using var input = File.OpenRead("payload.b64");
using var transform = new FromBase64Transform();
using var cryptoStream = new CryptoStream(input, transform, CryptoStreamMode.Read);
using var output = File.Create("payload.bin");
cryptoStream.CopyTo(output);Strumenti correlati
- Base64 Encoder — codifica testo o dati binari in Base64 nel browser, utile per generare fixture di test da incollare nei test unitari C#.
- JWT Decoder — decodifica e ispeziona tutti e tre i segmenti JWT in una volta, con ispezione campo per campo del payload — più veloce di scrivere un helper C# quando devi solo leggere un token.
- URL Decoder — decodifica stringhe con percent-encoding, utile quando le risposte API mescolano dati Base64url con parametri query percent-encoded.
- JSON Formatter — dopo aver decodificato un payload JWT Base64 o una configurazione API, incolla il JSON qui per formattarlo e validarne la struttura.