Skip to Content
Nueva versión 12 disponible 🎉
ObfuscatorPaquete NuGetProtección de secretos

Protección de secretos con cifrado de cadenas y valores

Casi todas las aplicaciones se distribuyen con secretos en el código: claves API, puntos de acceso, cadenas de conexión, parámetros de licencia, números «mágicos» y tablas de búsqueda. Un descompilador los lee en segundos. Este ejemplo usa el paquete NuGet de Babel Obfuscator para eliminar esos literales del ensamblado distribuido con el cifrado de cadenas y el cifrado de valores y matrices, sin cambiar una sola línea de código.

Para usar este ejemplo necesita una licencia de sitio de Babel Obfuscator (ediciones Ultimate, Server o Data Center). El código fuente está disponible en GitHub:

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

El proyecto de consola SecretApp hace referencia al paquete NuGet de Babel Obfuscator (solo para la compilación) y activa las dos capas de cifrado en 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>

El algoritmo de cadenas stream traslada todos los literales de cadena a una tabla cifrada, mientras que el cifrado de valores y matrices elimina del IL las constantes numéricas y las matrices en línea. Ambos se descifran a petición en tiempo de ejecución, de modo que el programa se comporta exactamente igual que antes mientras las constantes desaparecen del binario. Asignar W00000 a BabelWarningsAsErrors convierte en error una compilación en modo de evaluación, de modo que un binario sin proteger nunca puede distribuirse por accidente.

Los secretos están en 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 }; }

El ejemplo pone de relieve además un detalle importante: los secretos se declaran como static readonly, no como const. Un valor const queda grabado en los metadatos del ensamblado y se inserta en línea en cada lugar donde se usa, de modo que sobrevive a la ofuscación y sigue siendo legible; un campo static readonly se asigna con una instrucción ldstr/ldc que el cifrado de cadenas y de valores reescribe. Compilar el ejemplo en Release y buscar en los dos ensamblados confirma la diferencia: la clave API, el punto de acceso y la cadena de conexión están presentes en la compilación Debug y han desaparecido de la compilación Release, con una salida del programa idéntica.

Last updated on