Azure DevOps
Esegui Babel Obfuscator su Azure Pipelines referenziando il pacchetto NuGet di Babel Obfuscator da un feed privato di Azure Artifacts, con la licenza fornita come variabile segreta.
Azure Pipelines compila il progetto con l’SDK .NET, e il pacchetto Babel.Obfuscator inserisce il task Babel in quella build. Sull’agente non occorre installare Babel: il pacchetto contiene gli strumenti di build, e la pipeline deve soltanto autenticarsi presso il feed che lo ospita e fornire a Babel una licenza.
L’esempio usato in questa pagina è una piccola applicazione console:
git clone https://github.com/babelfornet/devops-integration.gitOspitare il pacchetto su un feed di Azure Artifacts
Il pacchetto Babel.Obfuscator non è pubblicato su nuget.org: lo ricevi con l’edizione Ultimate o con un’edizione per sede di Babel Licensing. Caricalo su un feed privato che solo la tua organizzazione può leggere.
Non caricare mai il pacchetto di Babel Obfuscator su un feed pubblico. Il pacchetto contiene gli strumenti di build di Babel, e ripubblicarlo viola i termini della tua licenza.
In Azure DevOps apri Artifacts, crea un feed con il nome Babel, poi carica il pacchetto:
dotnet nuget push Babel.Obfuscator.12.0.0.nupkg \
--source "https://pkgs.dev.azure.com/ORGANISATION/_packaging/Babel/nuget/v3/index.json" \
--api-key azAggiungi un file NuGet.config accanto alla soluzione, così sia il tuo computer sia l’agente di build risolvono il pacchetto da quel feed:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="babel" value="https://pkgs.dev.azure.com/ORGANISATION/_packaging/Babel/nuget/v3/index.json" />
</packageSources>
</configuration>Le credenziali sono volutamente assenti da questo file. Su un computer di sviluppo l’Azure Artifacts Credential Provider le chiede una sola volta; nella pipeline il task NuGetAuthenticate fornisce il token dell’identità di build. Nessuno dei due scrive un segreto nel repository.
Aggiungere il riferimento al pacchetto
Aggiungi il riferimento al pacchetto a ogni progetto di cui vuoi offuscare l’assembly:
<ItemGroup>
<PackageReference Include="Babel.Obfuscator" Version="12.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>PrivateAssets tiene il riferimento fuori dai pacchetti prodotti dal tuo progetto: Babel è uno strumento che serve in fase di build, non una dipendenza dell’assembly distribuito.
Fornire la licenza come segreto
Babel ha bisogno di una licenza per produrre un assembly che funzioni in modo permanente; senza licenza viene eseguito in modalità demo e l’output smette di funzionare dopo un breve periodo.
Non eseguire il commit di babel.licenses nel repository. Un file di licenza in un repository è leggibile da chiunque possa leggere il repository e da chiunque ne crei un fork, anche dopo che hai eliminato il file, perché il blob resta raggiungibile nel fork e nella cronologia del repository originale.
Salva invece la chiave di licenza come variabile segreta. Nella pipeline, in Variables, aggiungi BabelLicense e contrassegnala come segreta. Poi associala a una variabile d’ambiente nel passo di build e leggila dal progetto:
<PropertyGroup Condition="'$(BABEL_LICENSE)' != ''">
<BabelLicense>$(BABEL_LICENSE)</BabelLicense>
</PropertyGroup>La proprietà BabelLicense accetta il percorso di un file di licenza, una chiave di licenza oppure la chiave utente di una licenza flottante scritta come floating:<user key>. Su un agente di build conviene usare le ultime due, perché nessuna richiede un file su disco. In locale la proprietà resta non impostata e Babel usa il file babel.licenses della cartella del progetto o di una cartella superiore, così gli sviluppatori continuano a lavorare senza alcuna configurazione della pipeline. Vedi Configurazione del pacchetto.
La pipeline
trigger:
- main
pool:
vmImage: ubuntu-latest
variables:
buildConfiguration: Release
steps:
- task: UseDotNet@2
displayName: Install the .NET SDK
inputs:
version: 10.0.x
- task: NuGetAuthenticate@1
displayName: Authenticate to the Babel feed
- script: dotnet restore DevOpsIntegration.sln
displayName: Restore
- script: dotnet build DevOpsIntegration.sln --configuration $(buildConfiguration) --no-restore
displayName: Build and obfuscate
env:
BABEL_LICENSE: $(BabelLicense)
- task: PublishPipelineArtifact@1
displayName: Publish the obfuscated output
inputs:
targetPath: DevOpsIntegration/bin/$(buildConfiguration)/net10.0
artifact: DevOpsIntegrationDue dettagli meritano attenzione.
NuGetAuthenticate@1 è ciò che rende raggiungibile il feed privato. Configura il provider di credenziali con l’identità della pipeline, quindi il file NuGet.config riportato sopra non ha bisogno di una sezione packageSourceCredentials né di un tuo token.
Le variabili segrete non vengono passate automaticamente agli script: è proprio questo lo scopo di contrassegnarle come segrete. È il blocco env: del passo di build ad associare BabelLicense al processo, ed è l’unico punto in cui la chiave compare.
L’offuscamento viene eseguito come parte di dotnet build; non esiste un passo Babel separato. Il log di Babel compare nell’output della build, e un errore di licenza o di configurazione fa fallire il passo.
L’immagine dell’agente deve soltanto eseguire l’SDK .NET. ubuntu-latest è la scelta più economica e va bene per qualsiasi runtime di destinazione, perché Babel opera sull’IL: un agente Linux può offuscare assembly destinati a Windows. Usa windows-latest quando è la build stessa a richiedere Windows: target .NET Framework, WPF o Windows Forms.
Configurare l’offuscamento
Babel si configura con proprietà MSBuild nel file di progetto. Una soluzione comune è lasciare intatte le build Debug, così il debug in locale si comporta normalmente, e proteggere le build Release:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<BabelEnabled>false</BabelEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<StringEncryption>stream</StringEncryption>
<ControlFlowObfuscation>if=on;goto=on;switch=on;case=on;call=on</ControlFlowObfuscation>
<ControlFlowIterations>3</ControlFlowIterations>
<ResourceEncryption>true</ResourceEncryption>
</PropertyGroup>Tutte le proprietà sono elencate in Riferimento del pacchetto, e Configurazione dell’offuscamento spiega come corrispondono alle funzionalità di Babel.
Per tutto ciò che richiede più precisione di un’opzione valida per l’intero assembly, aggiungi un file di regole. La regola seguente esclude dall’offuscamento del flusso di controllo i metodi brevi, dove l’appiattimento (flattening) costa più di quanto nasconda:
<?xml version="1.0" encoding="utf-8" ?>
<Rules>
<Rule name="reduce control flow" feature="control flow" exclude="false" applyToMembers="true">
<Target>Classes,Structures</Target>
<Pattern>*</Pattern>
<Properties>
<MaxSwitchTargets>5</MaxSwitchTargets>
<MinInstructionCount>18</MinInstructionCount>
<UseValueEncryption>false</UseValueEncryption>
</Properties>
<Description>Do not scramble methods with few instructions.</Description>
</Rule>
</Rules>Indica il file alla build con la proprietà BabelRules:
<PropertyGroup>
<BabelRules>$(MSBuildThisFileDirectory)babelRules.xml</BabelRules>
</PropertyGroup>Verificare il risultato
Scarica l’artefatto della pipeline e controlla che l’assembly sia davvero offuscato, invece di darlo per scontato. L’esempio Rilevare l’offuscamento Babel mostra come eseguire questo controllo in modo automatico, e conviene aggiungerlo alla pipeline come verifica bloccante: altrimenti una licenza configurata male o un passo di build saltato fanno rilasciare un assembly non protetto senza che nulla fallisca.
Conserva il file map prodotto dalla build se intendi decodificare gli stack trace che arrivano dalla produzione. Vedi Decodifica degli stack trace.