Dopo aver visto caspol.exe nel post [MCAD.31] di ieri, ho trovato utile passare direttamente
a vedere gli strong names e la relativa l'utility sn.exe. Questa volta ho utilizzato come spunto questo articolo su codeproject.com , che spiega a cosa
servono gli strong names, come si fa a firmare (sign) un assemby con
uno strong name e quali scopi pratici ha.
A cosa serve uno strong name? Versioning e
Authentication
Lo risposta è già nel titolo di questo paragrafo.
Uno strong name è un meccanismo tramite il
quale vengono firmati gli assembly. Ad un assembly che viene firmato con uno
strong name viene garantito un nome univoco, tramite l'aggiunta di
informazioni/metadati come la versione (appunto), la localizzazione e così via.
Un assembly firmato può finire quindi nella GAC (Global Assembly Cache); di
conseguenza, tutti gli assembly nella GAC deve essere stati
firmati con uno strong name. Per esempio, basta andare nella directory
C:\WINNT\Assembly del proprio sistema per vedere tutti gli assembly della
propria GAC: tutti questi assembly sono firmati con uno strong name. Difatti,
ogni assembly possiede un Global Assembly Name, una
Version, una Culture ed una Public Key
Token. Passiamo altro.
A me però piace parlare degli strong name nel campo dell'authentication,
soprattutto perchè si lega con quello che abbiamo detto ieri, cioè Code Access
Security e quant'altro.
In
pratica, per esempio, possiamo assegnare agli assembly firmati con un certo
strong name le permissions per girare come FullTrust. Come? Creando un Code Group la cui
membership condition è propria quella di avere uno strong name uguale a "xyz", e
assegnando quindi a tale Code Group le permissions
FullTrust. Possiamo fare questa operazione
usando il .NET Framework 1.1 Configuration oppure usando l'utility
caspol.exe.
Ma andiamo con calma: prima vediamo di costruire una piccola applicazione che
legga nel registry di Windows e vediamo che problematiche di security ci
sono.
Problemi di security: My_Computer_Zone e
LocalIntranet_Zone
Ho creato un'applicazione Windows Forms,
ReadRegistry. Una sola form ed una sola TextBox. Nel costruttore ho inserito il
seguente codice:
//
// TODO: Add any constructor code after InitializeComponent call
//
Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.CurrentUser;
this.txtReading.Text = rk.OpenSubKey(@"Software").SubKeyCount.ToString();
Compiliamo, eseguiamo. Tutto ok, nella TextBox appare "33". Proviamo adesso a
copiare l'EXE appena generato in uno share di rete qualsiasi: va bene anche il
nostro stesso PC, l'importante è che l'EXE venga lanciato da
\\nome_pc\nome_dir\nome_exe. Questa volta abbiamo una
SecurityException.
Perchè? Nel primo caso, l'EXE veniva eseguito da
My_Computer_Zone, che gira come FullTrust. Nel
secondo caso gira da LocalIntranet_Zone, che non ha diritti di lettura dal registry.
Risultato: exception. Come risolviamo la questione? La prima cosa da fare
è firmato l'EXE con uno strong name, successivamente dare i permessi corretti per
farlo girare senza problemi.
Firmare un assembly con lo strong name
Apriamo la command-line di VS,
e finalmente usiamo sn.exe. Diamo il comando:
sn -k C:\Key.snk
Questo comando scrive il file C:\Key.snk contenente una coppia di chiavi
(pubblica & privata) che utilizzeremo fra qualche
istante per firmare il nostro assembly.
Torniamo a Visual Studio (se l'avete chiuso, male: riapritelo subito!!! ). Guardiamo la window Solution
Explorer, apriamo il file AssemblyInfo.cs. Questo
file contiene diversi attribute che il compilatore utilizza per decorare il
nostro assembly finale. Cerchiamo l'attribute AssemblyKeyFile e
modifichiamolo in:
[assembly: AssemblyKeyFile(@"C:\\Key.snk")]
Ricompiliamo l'applicazione. Questa volta, l'EXE è stato firmato con lo
strong name contenuto in C:\Key.snk. Possiamo semplicemente verificarlo con il
comando:
sn -v ReadRegistry.exe
che ci risponde "Assembly 'ReadRegistry.exe' is valid". Bene, cosa facciamo
ora? Se eseguiamo il nuovo EXE dal nostro disco locale non cambia nulla. Se lo
eseguiamo dallo share di rete, ancora SecurityException! Cosa
c'è che non va? Beh, l'exception è normale: comunque sia, il nostro EXE gira
dalla zone LocalIntranet_Zone, per cui i permessi sono limitati.
Quello che dobbiamo fare è, come dicevo prima, creare un nuovo code group a
cui possa appartenere il nostro assembly, e dare a questo code group i permessi
FullTrust. Come facciamo?
Un nuovo code group con pieni poteri!
Creiamo un nuovo
code group con le seguenti caratteristiche:
- Il nome sarà ReadRegistry
- La membership condition necessaria sarà quella di
avere lo stesso strong name del nostro EXE appena compilato
- I permessi saranno FullTrust
- Incastreremo il nuovo code group all'interno del nodo
LocalIntranet_Zone
La sintassi di caspol.exe è piuttosto complessa, ho fatto diversi tentativi
prima di trovare quella giusta. La logica c'era, i parametri erano quelli
giusti, ma l'ordine deve essere quello giusto, altrimenti caspol.exe risponde
picche. Il comando giusto è:
caspol
-addgroup 1.2.
-strong
-file "D:\Documenti\Visual Studio Projects\ReadRegistry\bin\Debug\ReadRegistry.exe"
-noname -noversion
FullTrust
-name "ReadRegistry"
Ovviamente, va lanciato tutto su una riga sola, trattandosi di un buon
vecchio comando DOS. I parametri che ho passato sono i seguenti:
-addgroup 1.2.
crea il nuovo
code group dentro il 2° nodo del 1° nodo (in pratica, dentro
LocalIntranet_Zone, a sua volta dentro
All_Code)
-strong -file <nome_file>
crea la membership condition del nuovo code group. In questo caso,
la condition deriva dal fatto di avere lo stesso strong name incluso nel file
passato come parametro
-noname -noversion
la
membership condition considera solo lo strong name, ignorando il nome esatto
dell'assembly e la sua version
FullTrust
permission sets
associato a questo code group
-name "<nome_code_group>"
dà un nome al code group appena creato
Risultato? Nessun SecurityException
Se caspol.exe ha
fatto il suo dovere fino in fondo, aprendo il tool .NET Framework 1.1
Configuration, vediamo il nuovo code group indentato in
LocalIntranet_Zone. Tutti quegli assembly che verranno lanciati
dalla Intranet o da uno share di rete e che conterranno quello strong name,
apparterranno a questo code group, e pertanto gireranno come
FullTrust
Eseguiamo il nostro EXE dal solito share di rete (senza ricompilare,
ovviamente) e questa volta non c'è alcuna SecurityException. Missione
compiuta!!!!
powered by IMHO
1.2