Certificato TLS/SSL autofirmato su Windows Server 2022 (workgroup): come evitare gli avvisi dei browser

Vuoi presentare un server demo Windows Server 2022 (workgroup) che espone IIS, API REST e SQL Server su HTTPS senza l’odioso avviso “connessione non sicura”? Qui trovi perché il certificato autofirmato non basta e le soluzioni che funzionano davvero, con procedure passo‑passo.

Indice

Perché un certificato autofirmato non è “trasparente” ai browser

I browser considerano sicure solo le connessioni protette da certificati firmati da una Certification Authority (CA) presente nel loro trust store. Un certificato autofirmato (self‑signed) non è garantito da alcuna CA e quindi viene segnalato come potenzialmente insicuro. È possibile evitare l’avviso soltanto se ogni singolo client installa e considera attendibile la radice (o il certificato) usato dal server.

Su Windows la maggior parte dei browser si appoggia allo store di certificati del sistema operativo. Altri browser possono avere un archivio proprio o opzioni per usarlo. In ogni caso, se la chiave pubblica della CA non è già nel trust store del client, il messaggio d’allerta comparirà sempre, a prescindere da quanto “robusto” sia l’algoritmo usato (RSA, ECDSA, SHA‑256, ecc.).

Scenari pratici: pro e contro

OpzioneCome funzionaVantaggiSvantaggi
A. Importare il certificato autofirmato su ogni clientGeneri la coppia chiave privata/certificato (PowerShell New‑SelfSignedCertificate o openssl). Esporti il certificato in .cer (solo parte pubblica). Lo installi manualmente (o via GPO/MDM) in Trusted Root Certification Authorities su ogni dispositivo che dovrà accedere.Gratis. Nessuna dipendenza da DNS pubblico.Devi toccare tutti i client (spesso impossibile in demo da cliente). Ogni nuovo device richiede la stessa operazione e manutenzione periodica.
B. Creare una CA privata aziendaleCrei una root CA (con openssl o, in ambienti AD, con AD CS). Usi la root per firmare un certificato server per il nome interno (es. demo.local). Distribuisci la root ai client (una tantum). I certificati server successivi saranno fidati automaticamente.Rinnovi/rigeneri i certificati server senza toccare i client. Controllo completo della PKI.Serve comunque distribuire la root ai client esterni. Poco pratico se il server cambia rete o nome DNS frequentemente.
C. Ottenere un certificato da CA pubblicaUsi (o registri) un FQDN pubblico, es. demo.azienda.it. Richiedi un certificato a una CA pubblica o via ACME (es. Let’s Encrypt) con validazione DNS. Installi il certificato su IIS/SQL/Kestrel e lo rinnovi periodicamente.Nessun avviso su qualunque browser standard, nessuna distribuzione lato client. Funziona anche con device non gestiti (BYOD del cliente).Richiede dominio pubblico e gestione DNS (inclusi record interni coerenti). Rinnovo periodico (es. 90 giorni con Let’s Encrypt).
D. Reverse‑proxy con terminazione TLSEsegui il server demo in HTTP interno e pubblichi tramite un reverse‑proxy/WAF (nginx, traefik, ecc.) in DMZ con certificato pubblico.Un unico certificato esterno per più back‑end. Semplifica IIS/Kestrel/SQL sul nodo demo.Aggiunge infrastruttura e complessità: spesso eccessivo per demo itineranti.

Risposta breve

  • Non esiste un modo perché un autofirmato sia universalmente riconosciuto dai browser senza installare la relativa radice su ciascun client.
  • Per una demo “a casa del cliente” la soluzione più realistican è: (a) CA privata con distribuzione controllata della root se puoi toccare i device; (b) certificato pubblico su FQDN tuo se non puoi toccarli.

Prerequisiti e concetti chiave

  • Naming: il nome nel certificato deve corrispondere esattamente all’URL usato dai client. Oggi i browser si basano sul Subject Alternative Name (SAN), non più sul solo Common Name.
  • Chiavi e algoritmi: usa almeno RSA 2048 e SHA‑256. Per demo brevi non serve oltre.
  • Archivi: su Windows Server installa i certificati nel Computer store (Local Computer\Personal). Per la fiducia lato client, usa Trusted Root Certification Authorities.
  • SQL Server: richiede un certificato con EKU “Server Authentication” e chiave privata accessibile al servizio. Il CN/SAN deve combaciare con il nome usato nella stringa di connessione.
  • TLS: nel 2025 è consigliato negoziare almeno TLS 1.2 (idealmente TLS 1.3 dove disponibile).

Procedura consigliata: CA privata se puoi toccare i client

Questo flusso consente di evitare l’avviso sui browser dei dispositivi “preparati” installando una root CA comune. È ideale quando porti tu i laptop di demo o quando il cliente ti autorizza a pre‑configurare i suoi device “fidati”.

Passo 1 — Creare una root CA con OpenSSL

# Genera la chiave privata della root CA
openssl genrsa -out rootCA.key 4096

Crea il certificato della root (validità 10 anni)

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 
-subj "/C=IT/O=Demo/OU=Root CA/CN=demo-root" -out rootCA.crt 

Passo 2 — Generare la richiesta e il certificato server (con SAN)

# Chiave e CSR per il server (CN e SAN)
openssl req -new -nodes -out server.csr -newkey rsa:2048 -keyout server.key \
  -subj "/C=IT/O=Demo/CN=demo.local" \
  -addext "subjectAltName=DNS:demo.local,IP:192.168.1.50"

Firma la CSR con la root; 825 giorni è una scadenza tipica

openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key 
-CAcreateserial -out server.crt -days 825 -sha256 

Passo 3 — Creare un PFX e importarlo su Windows Server

# Crea un PFX (include server.crt, server.key e la root CA per la chain)
openssl pkcs12 -export -name "Demo TLS" \
  -inkey server.key -in server.crt -certfile rootCA.crt -out server.pfx
# Importa il PFX nello store del computer locale
$pwd = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
Import-PfxCertificate -FilePath "C:\temp\server.pfx" `
  -Password $pwd -CertStoreLocation Cert:\LocalMachine\My | Out-Null

Passo 4 — Distribuire la root ai client

Copia rootCA.crt su ciascun client e installalo in Autorità di certificazione radice attendibili (archivio del computer). Puoi automatizzare con:

# Installazione root CA su Windows (eseguito come amministratore)
Import-Certificate -FilePath ".\rootCA.crt" -CertStoreLocation Cert:\LocalMachine\Root

Su smartphone e macOS esistono procedure analoghe: l’obiettivo è aggiungere la root allo store di fiducia del dispositivo.

Passo 5 — Binding HTTPS in IIS

  1. Apri Internet Information Services (IIS) ManagerSites → seleziona il sito.
  2. Bindings…Addhttps, porta 443, Host name demo.local (se usi SNI), seleziona il certificato importato.

PowerShell (WebAdministration):

Import-Module WebAdministration
$site = "Default Web Site"
$thumb = (Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -like "CN=demo.local"}).Thumbprint
Crea il binding HTTPS (SNI abilitato con SSLFlags=1)
if (-not (Get-WebBinding -Name $site -Protocol https -ErrorAction SilentlyContinue)) {
  New-WebBinding -Name $site -Protocol https -Port 443 -HostHeader "demo.local" | Out-Null
}
New-Item "IIS:\SslBindings\0.0.0.0!443!demo.local" -Thumbprint $thumb -SSLFlags 1 -Force | Out-Null

Passo 6 — Configurare SQL Server con TLS

  1. Apri SQL Server Configuration ManagerSQL Server Network ConfigurationProtocols for MSSQLSERVERProperties.
  2. Nel tab Certificate scegli il certificato (deve essere in Local Computer\Personal, con chiave privata ed EKU “Server Authentication”).
  3. Facoltativo: in Flags imposta Force Encryption = Yes.
  4. Riavvia il servizio SQL Server.

Esempio di stringa di connessione client sicura:

Server=tcp:demo.local,1433;Database=DemoDb;Encrypt=True;TrustServerCertificate=False;...

Nota: TrustServerCertificate=True elimina l’avviso ma by‑passa la convalida della chain. Usalo solo per test non sensibili.

Passo 7 — API REST su Kestrel/HTTP.sys

Per un’API .NET su Kestrel puoi referenziare il PFX in appsettings.json:

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://0.0.0.0:5001",
        "Certificate": {
          "Path": "C:\\certs\\server.pfx",
          "Password": "P@ssw0rd!"
        }
      }
    }
  }
}

Oppure usa HTTP.sys:

# Binding TLS sullo stack HTTP.sys (se non usi IIS)
$thumb = (Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -like "CN=demo.local"}).Thumbprint
netsh http add sslcert ipport=0.0.0.0:5001 certhash=$thumb appid="{00112233-4455-6677-8899-AABBCCDDEEFF}"

Procedura alternativa: certificato pubblico con validazione DNS (quando non puoi toccare i client)

Se non puoi installare nulla sui dispositivi del cliente, usa un FQDN pubblico e un certificato emesso da CA pubblica. La validazione DNS‑01 è perfetta anche quando il server non è esposto a Internet.

  1. Registra o usa un dominio (es. azienda.it) e scegli un hostname (es. demo.azienda.it).
  2. Richiedi il certificato con un client ACME (ad es. uno strumento che supporta challenge DNS manuale o tramite API DNS). Il tool ti chiederà di pubblicare un record TXT su _acme-challenge.demo.azienda.it con un valore specifico. Pubblicalo, attendi la propagazione, poi completa l’ordine per ottenere un .pfx.
  3. DNS interno coerente: in rete demo, risolvi demo.azienda.it all’indirizzo privato del server (via DNS locale o hosts su client demo).
  4. Installa e lega il certificato su IIS/SQL/Kestrel come sopra. I browser lo considereranno fidato senza ulteriori operazioni.
  5. Automatizza il rinnovo: programma il client ACME in attività pianificate (i certificati pubblici tipicamente scadono ogni 90 giorni).

Generare un autofirmato direttamente con PowerShell (SAN incluso)

Per prove rapide puoi creare un certificato server direttamente su Windows Server 2022:

# Crea un certificato server con SAN e lo mette nello store del computer
$dns = @("demo.local","192.168.1.50")
$cert = New-SelfSignedCertificate `
  -DnsName $dns `
  -CertStoreLocation "Cert:\LocalMachine\My" `
  -KeyAlgorithm RSA -KeyLength 2048 -HashAlgorithm SHA256 `
  -NotAfter (Get-Date).AddDays(825) `
  -FriendlyName "Demo TLS"

(Facoltativo) Esporta PFX se devi usarlo in Kestrel/altre macchine

$pwd = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
Export-PfxCertificate -Cert $cert -FilePath "C:\temp\server.pfx" -Password $pwd | Out-Null 

Attenzione: questo certificato resta autofirmato; per evitare avvisi sui client devi installarlo (o installare la sua radice) in ognuno di essi.

DNS e nomi: come evitare gli errori più comuni

  • Name mismatch: il browser confronta l’URL con i valori in SAN. Se usi https://192.168.1.50, il SAN deve includere IP:192.168.1.50. Se usi https://demo.local, il SAN deve includere DNS:demo.local.
  • Hostnames multipli: aggiungi tutti i nomi necessari (es. demo, demo.local, demo.azienda.it) nel SAN. Evita wildcard inutili: non aggiungono fiducia lato client.
  • Risoluzione coerente: interno e esterno devono risolvere lo stesso hostname all’IP corretto. Se usi un FQDN pubblico in rete privata, crea record DNS interni o usa hosts temporaneamente.

Hardening e buone pratiche

  • Chiave privata al sicuro: proteggi il PFX con password robusta; limita l’accesso alla chiave (tasto destro sul certificato → Manage Private Keys…).
  • EKU appropriati: per i server usa “Server Authentication”. Evita di riutilizzare certificati client per il server.
  • Algoritmi moderni: RSA ≥ 2048, SHA‑256. Elliptic Curve è ok ma può complicare interop in ambienti legacy.
  • TLS: abilita almeno TLS 1.2; verifica la conformità dell’applicazione e dei client.
  • Automazione: pianifica i rinnovi (script o client ACME). Non lasciare scadere i certificati: i browser bloccano la navigazione.
  • Backup: salva in posto sicuro chiavi e PFX (oltre alla root CA, se usi una PKI privata).
  • Audit e revoca: in una CA privata, prevedi processi minimi per revocare e rigenerare certificati compromessi.

mkcert: scorciatoia per ambienti di sviluppo

mkcert crea una piccola CA locale e installa automaticamente la radice nel trust store del tuo PC (e dei browser principali). È comodo per laboratori e test, ma non risolve il problema con i device del cliente: su quei dispositivi la root andrebbe comunque installata.

Troubleshooting: errori tipici e come risolverli

  • NET::ERRCERTAUTHORITY_INVALID / “L’autorità non è attendibile” — La root CA non è installata sul client. Installa la root nel trust store del dispositivo.
  • ERRCERTCOMMONNAMEINVALID / name mismatch — L’URL non corrisponde al SAN del certificato. Rigenera o aggiungi i SAN corretti.
  • “A specified logon session does not exist” al binding IIS — Il processo non vede la chiave privata o il certificato è in un archivio errato. Importa nel Local Computer\Personal, verifica i permessi della chiave (IIS_IUSRS) e, se necessario, riesporta il PFX con “chiave esportabile”.
  • SQL Server non mostra il certificato — Mancano EKU “Server Authentication” o chiave privata, oppure il CN/SAN non coincide con il nome del server nella stringa di connessione. Correggi e riavvia il servizio.
  • Client .NET vecchi — Forza TLS 1.2 se necessario (solo per app legacy):
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
  • Catena incompleta — Se usi una CA intermedia, includila nel PFX (-certfile in OpenSSL) così che i client costruiscano correttamente la chain.

Esempio “end‑to‑end” per una demo itinerante

  1. Decidi lo scenario:
    • Puoi toccare i device? → CA privata + distribuzione root.
    • Non puoi? → FQDN pubblico + certificato pubblico (DNS‑01).
  2. Scegli il nome (es. demo.azienda.it oppure demo.local + IP nel SAN).
  3. Genera ed installa il certificato (PFX in LocalMachine\My).
  4. Binding HTTPS su IIS (SNI se multi‑sito) e su Kestrel/HTTP.sys per l’API.
  5. Configura SQL Server con il certificato, valuta Force Encryption.
  6. Test da un client: verifica padlock verde e assenza di avvisi; esegui una query HTTPS e una connessione SQL con Encrypt=True.
  7. Automatizza rinnovi e documenta la procedura (chi fa cosa, quando).

FAQ rapide

Posso usare un certificato wildcard autofirmato (*.demo.local)?
Sì tecnicamente, ma non aggiunge fiducia: i client continueranno a segnalarlo. Inoltre può complicare il matching dei nomi. Meglio elencare i SAN necessari.

Se aggiungo l’IP nel CN basta?
No. I browser moderni ignorano il CN per la convalida: usa il SAN (DNS: e/o IP:).

È sicuro impostare TrustServerCertificate=True in SQL?
È una scorciatoia per test rapidi ma disattiva la convalida del certificato: evita in demo con dati reali.

Quanto deve durare un certificato demo?
Per ambienti demo 3–12 mesi sono ragionevoli. I certificati pubblici emessi via ACME in genere scadono dopo 90 giorni: pianifica il rinnovo.

Checklist finale

  • Il nome richiesto dai client è presente nel SAN (DNS e/o IP)?
  • Il certificato è nel Local Computer\Personal e la chiave privata è accessibile al processo?
  • Se usi CA privata, la root è installata su tutti i client?
  • SQL Server vede il certificato con EKU “Server Authentication”?
  • Binding HTTPS attivo su IIS/Kestrel/HTTP.sys senza sovrapposizioni di porta?
  • Rinnovi automatizzati e documentati?

Conclusioni

  • No, un certificato autofirmato non può diventare “invisibile” agli avvisi dei browser se non installi la relativa radice su ogni dispositivo.
  • , puoi ottenere connessioni senza allerta se:
    • controlli i client e distribuisci la root CA (CA privata), oppure
    • usi un certificato pubblico per un FQDN coerente con la risoluzione DNS.
  • Scegli la strategia in base a quanto controllo hai sui device e alla natura della demo (itinerante vs. interna).

Appendice: script PowerShell per import e binding IIS

# Parametri
$SiteName   = "Default Web Site"
$HostHeader = "demo.local"
$PfxPath    = "C:\temp\server.pfx"
$PfxPass    = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force

1) Import certificato nel Computer store

$cert = Import-PfxCertificate -FilePath $PfxPath -Password $PfxPass -CertStoreLocation Cert:\LocalMachine\My

2) Crea/aggiorna binding HTTPS con SNI

Import-Module WebAdministration
if (-not (Get-WebBinding -Name $SiteName -Protocol https -HostHeader $HostHeader -ErrorAction SilentlyContinue)) {
New-WebBinding -Name $SiteName -Protocol https -Port 443 -HostHeader $HostHeader | Out-Null
}
$thumb = $cert.Thumbprint
New-Item "IIS:\SslBindings\0.0.0.0!443!$HostHeader" -Thumbprint $thumb -SSLFlags 1 -Force | Out-Null

Write-Host "Binding HTTPS configurato su $SiteName ($HostHeader) con cert $thumb" 

Appendice: esempio OpenSSL completo (CA privata + server)

# Root CA
openssl genrsa -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 \
  -subj "/C=IT/O=Demo/OU=Root CA/CN=demo-root" -out rootCA.crt

Server CSR (SAN: dominio e IP privato)

openssl req -new -nodes -out server.csr -newkey rsa:2048 -keyout server.key 
-subj "/C=IT/O=Demo/CN=demo.local" 
-addext "subjectAltName=DNS:demo.local,IP:192.168.1.50"

Firma e PFX

openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key 
-CAcreateserial -out server.crt -days 825 -sha256
openssl pkcs12 -export -name "Demo TLS" -inkey server.key -in server.crt 
-certfile rootCA.crt -out server.pfx 

Appendice: note su permessi chiave privata

Se IIS o il servizio SQL non riescono ad aprire la chiave privata, apri MMC → Certificates (Local Computer), vai su Personal, tasto destro sul certificato → All TasksManage Private Keys…, e accorda l’accesso al gruppo di servizio (es. IIS_IUSRS o l’account del servizio SQL). Questo elimina errori di binding e handshake TLS.


In sintesi operativa: per una demo credibile e senza attriti, pensa prima al nome (DNS) e al perimetro (chi sono i client). Poi scegli tra CA privata (se li controlli) o certificato pubblico (se non li controlli). Il resto è pura implementazione tecnica.

Indice