Windows Web Services API : Configurazione Certificati e sicurezza per gli esempi con SSL


Tutti gli esempi che ho creato nei post precedenti erano su HTTP quindi senza sfruttare la sicurezza di trasporto (SSL). Ora vediamo quali passi sono necessari per configurare la comunicazione su SSL (uso questo esempio su MSDN )


IMPORTANTE !!! In questo post alcune delle configurazioni che faccio sui certificati digitali possono risultare molto pericolose su macchine di produzione… In un ambiente di produzione il rilascio,l’installazione e la manutenzione dei certificati deve essere seguito secondo i processi definiti dalla PKI !! Al contrario, sulle macchine dei sviluppatori spesso risulta necessario farsi delle configurazioni ad hoc per essere autonomi rispetto ai colleghi sistemisti 🙂 :-). Per facilitare la cosa metterò un tag <WARNING!!> su tutte quelle procedure da non riprodurre in produzione !!


Innanzitutto i passaggi per impostare i progetti client e service e il processo di creazione dei file .c e .h dal wsdl sono sempre i medesimi descritti qui e qui.


Per far si che il nostro Web Service possa utilizzare il protocollo SSL è necessario configurare quale certificato verrà utilizzato per l’inizializzazione del protocollo. Ce lo ricorda anche un commento nel codice presente in tutti gli esempi su MSDN che utilizzano SSL



// NOTE: At the server, the SSL certificate for the listen URI must be
// registered with http.sys using a tool such as httpcfg.exe.


Questa operazione andrà eseguita perchè faremo noi l’hosting del Web Service all’interno di una Win32 console al posto di IIS !!


In questo post utilizzerò l’utility netsh.exe invece di httpcfg.exe


Per prima cosa dovremo procurarci un certificato digitale X509v3. Se non riusciamo ad avere in tempo un certificato da una CA allora seguite questi semplici passi:


<WARNING!!>


usiamo l’utility makecert.exe per creare ed installare il certificato nel certificate store di Windows. (maggiori info sui certificati e sugli store in Windows). Apriamo una console di Visual Studio in Administrator mode e lanciamo :


makecert -r -pe -n "CN= 127.0.0.1" -b 01/01/2009 -e 01/01/2036 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12


</WARNING!!>


Tramite questo comando abbiamo creato un certificato per “Ensure the identity of a remote computer” e “All issuance policies” ed è stato installato nel certificate store della macchina (local machine). Apriamo la mmc dei certificati e clicchiamo sul certificato in Certificates (Local Computer)->Personal->Certificates e dovremmo vedere una cosa simile a quanto riportato in figura.


image


a questo punto se proviamo a lanciare il nostro esempio riceviamo il seguente errore :



Failure: errorCode=0x803d0014
There was an error communicating with the endpoint at '
https://127.0.0.1:8999/example’.
The connection with the server was terminated abnormally


questo perchè non abbiamo ancora creato il binding tra l’URI e il certificato digitale nel nostro kernel mode http listener(Http.sys) e quindi il protocollo SSL non può funzionare.  Infatti se lanciamo il seguente comando :



netsh http show sslcert


abbiamo una lista dei certificati configurati per SSL con relativo IP:port e hash del certificato! Ovviamente il nostro 127.0.0.1:8999 non esiste. Quindi lo creiamo lanciando il seguente comando :



netsh http add sslcert ipport=127.0.0.1:8999 certhash=a455de0b81ce3251d177d9fb74c62fe237a49ae1 appid={00112233-4455-6677-8899-AABBCCDDEEFF}


In questo caso abbiamo impostato il parametro ipport=127.0.0.1:8999 e certhash con l’hash del nostro certificato appena creato. Per ottenere il valore dell’hash dobbiamo aprire il certificato e alla voce Thumbprint nella tab Details copiare il contenuto. Ricordarsi di togliere gli spazi !!!


image


se ora rilanciamo il comando



netsh http show sslcert


potremo vedere il nuovo binding sulla porta 8999


image


Se proviamo ora a lanciare il nostro esempio riceviamo un altro errore:



Failure: errorCode=0x803d000a
There was an error communicating with the endpoint at '
https://127.0.0.1:8999/example’.
The certificate authority is invalid or incorrect


infatti come si vede anche dalla figura 1 il certificato che abbiamo creato ed installato non è valido dal punto di vista della “Certification path”. Per rimediare a questo problema basta copiare il certificato da


<WARNING!!>



Certificates (Local Computer)->Personal->Certificates



Certificates (Local Computer)->Trusted Root Certification Authorities->Certificates


</WARNING!!>


a quel punto, se riclicchiamo sul certificato all’interno di Certificates (Local Computer)->Personal->Certificates avremo :


image


che ci assicura che tutta la “Certification path” è corretta.


Finalmente, se ora lanciamo il  Web Service e il client il tutto funziona con il protocollo SSL !!!! Finito?? Non direi 🙂


NOOOOO… UN WEB SERVICE CHE GIRA SOLO COME ADMINISTRATOR???


In effetti, se ci fermiamo qui i nostri Web Services girano solo se hanno le credenziali di amministratore !!! Orrore !!! Infatti se creiamo due local Users demo1 e demo2 (aggiungere la policy longon locally se si tratta del server) e dalla nostra console amministrativa lanciamo



runas /user:demo1 cmd.exe (dopo l’invio ci chiede la password)


runas /user:demo2 cmd.exe (dopo l’invio ci chiede la password)


se nella cmd di demo1 ad esempio lanciamo il nostro service (che prima funzionava nella console che gira come admin) avremo come risposta :



Failure: errorCode=0x80070005
Unable to add URL to HTTP URL group.
Access is denied.


Per superare questo ultimo scoglio dobbiamo assegnare i permessi ad un gruppo di utenti (o ad un singolo utente nel nostro caso, per semplicità) per un determinato HTTP URL namespace. Con questa operazione di fatto diamo la possibilità di creare dei servizi di listener su determinati URL a tutti i processi che girano con le credenziali definite. Questa operazione verrà effettuata, ad esempio, durante il processo di installazione dei nostri servizi. Per fare questa operazione lanciamo il comando :



Netsh http add urlacl url=https://127.0.0.1:8999/example user=demo1


e possiamo visualizzare il nuovo namespace reservation tramite il comando :



Netsh http show urlacl


image


a questo punto se rilanciamo il servizio sempre dalla console demo1 … funzionerà !!!  mentre se lo lanciamo dalla console demo2 no !!


image


La prova del nove? Dalla console amministrativa lanciate il comando:



Netsh http delete urlacl url=https://127.0.0.1:8999/example


che cancella nuovamente la reservation e vedrete che se rilanciate il vostro Web service sempre dalla console demo1 non funzionerà nuovamente 🙂


Un paio di Curiosità


1) Dove vengono registrate le info di netsh.exe ?


Tutte le impostazioni vengono salvate nel registy :


HKLM\SYSTEM\CurrentControlSet\Services\HTTP\Parameters\SslBindingInfo


image


e in


HKLM\SYSTEM\CurrentControlSet\Services\HTTP\Parameters\UrlAclInfo



image



2) Quali API devo utilizzare per crearmi programmaticamente una URL reservation?


Le API di riferimento sono le HTTP Server API Reference.
Alla fine il tutto si risolve tramite le API



ULONG HttpInitialize( __in HTTPAPI_VERSION Version,
__in ULONG Flags,
__reserved PVOID pReserved );


e


ULONG HttpSetServiceConfiguration(
__in HANDLE ServiceHandle,
__in HTTP_SERVICE_CONFIG_ID ConfigId,
__in PVOID pConfigInformation,
__in ULONG ConfigInformationLength,
__in LPOVERLAPPED pOverlapped
);

Stavo per scrivere il wrapper in C# via p/Invoke ma grazie a Keith Brown ho risparmiato almeno un’oretta di lavoro :-). Anche in questo caso, esclusi i vari controlli il tutto si riduce nelle due chiamate alle HTTP API.



// Inizializzazioni varie delle HTTP API



// Impostazione delle ACL


int errorCode = HttpInitialize(httpApiVersion,HTTP_INITIALIZE_CONFIG, IntPtr.Zero);


errorCode = HttpSetServiceConfigurationAcl(IntPtr.Zero, HttpServiceConfigUrlAclInfo,ref configInfo, Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_SET)),IntPtr.Zero);


//Chiamte a Funzioni HTTPAPI di CleanUp…



Infine, mi raccomando di ricordarsi di cancellare o disattivare gli utenti locali demo1 e demo2 e di cancellare i certificati quanto prima !!!


--Mario

Comments (3)

  1. Sono appena tornato dal Delphi Day 2009, il secondo per me, dopo quello del 2007. Marco Cantù è stato

  2. jpsand@charter.net says:

    Great Blog.  I used Bing to translate it from Italian to English.  Then I was able to resolve my issue of running as a non admin using C:Windowssystem32>netsh http add urlacl url=http://+:80/example user=myDOMAINmyUSERNAME.  Thanks!

Skip to main content