Skip to Content
Nuova versione 12 disponibile 🎉
ObfuscatorPacchetto NuGetProtezione dei segreti

Proteggere i segreti con la cifratura di stringhe e valori

Quasi ogni applicazione contiene segreti nel proprio codice: chiavi API, endpoint, stringhe di connessione, parametri di licenza, numeri “magici” e tabelle di ricerca. Un decompilatore li legge in pochi secondi. Questo esempio usa il pacchetto NuGet di Babel Obfuscator per rimuovere questi valori letterali dall’assembly distribuito con la cifratura delle stringhe e la cifratura di valori e array, senza cambiare una riga di codice.

Per usare questo esempio ti serve una licenza per sede di Babel Obfuscator (edizioni Ultimate, Server o Data Center). Il codice sorgente è disponibile su GitHub:

git clone https://github.com/babelfornet/secret-protection-nuget-example.git

Il progetto console SecretApp fa riferimento al pacchetto NuGet di Babel Obfuscator (usato solo per la build) e attiva i due strati di cifratura in Release:

<ItemGroup Condition="'$(Configuration)' == 'Release'"> <PackageReference Include="Babel.Obfuscator" Version="12.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <PropertyGroup Condition="'$(Configuration)' == 'Release'"> <StringEncryption>stream</StringEncryption> <ValueEncryption>int32=true;int64=true;single=true;double=true;array=true;true</ValueEncryption> <ControlFlowObfuscation>if=true;switch=true;case=true;chain=true;true</ControlFlowObfuscation> <BabelWarningsAsErrors>W00000</BabelWarningsAsErrors> </PropertyGroup>

L’algoritmo per le stringhe stream sposta ogni valore letterale stringa in una tabella cifrata, mentre la cifratura di valori e array rimuove dall’IL le costanti numeriche e gli array inline. Entrambi vengono decifrati su richiesta in fase di esecuzione, quindi il programma si comporta esattamente come prima mentre le costanti scompaiono dal file binario. Impostare BabelWarningsAsErrors su W00000 trasforma in errore una build in modalità demo, così un file binario non protetto non può mai essere rilasciato per sbaglio.

I segreti si trovano in src/SecretApp/Secrets.cs:

internal static class Secrets { // Strings -> removed by String Encryption (stream) public static readonly string ApiKey = "DEMO-API-KEY-0000-1111-2222-3333-4444-5555"; public static readonly string ServiceEndpoint = "https://api.internal.example.com/v3/ingest"; public static readonly string ConnectionString = "Server=db.internal;Database=Orders;User Id=svc;Password=__DEMO_PLACEHOLDER__;"; // Numbers -> removed by Value Encryption public static readonly int ApiPort = 8443; public static readonly double RiskThreshold = 0.8734; // Lookup table -> removed by Array Encryption public static readonly int[] RolloutBuckets = { 12, 47, 63, 88, 91, 128, /* … */ 8192, 9001 }; }

L’esempio mette in evidenza anche un dettaglio importante: i segreti sono dichiarati static readonly, non const. Un valore const viene scritto nei metadati dell’assembly e copiato inline in ogni punto di utilizzo, quindi sopravvive all’offuscamento e resta leggibile; un campo static readonly viene assegnato con un’istruzione ldstr/ldc che la cifratura delle stringhe e dei valori riscrive. Compilando l’esempio in Release e cercando nei due assembly si conferma la differenza: la chiave API, l’endpoint e la stringa di connessione sono presenti nella build Debug e assenti dalla build Release, con un output del programma identico.

Last updated on