SSH: il protocollo che tiene in piedi Internet

Se c'è un protocollo che più di ogni altro tiene in piedi l'infrastruttura digitale mondiale, quello è SSH. Secure Shell è il modo standard con cui milioni di amministratori di sistema, sviluppatori e ingegneri accedono ogni giorno a server remoti, gestiscono infrastrutture cloud, eseguono deployment di codice, controllano router e dispositivi IoT, e trasferiscono file in modo sicuro. È uno strumento che esiste da trent'anni, è rimasto essenzialmente invariato nella sua interfaccia utente, ed è diventato talmente fondamentale che è difficile immaginare come funzionerebbe Internet senza di esso.

Le origini: la storia di Tatu Ylonen e il 1995

Prima di SSH, il modo standard per accedere a sistemi Unix remoti era Telnet, un protocollo che trasmetteva tutto in chiaro: username, password, ogni singolo comando digitato. In un'epoca in cui Internet era ancora una rete accademica e relativamente fidata, questo era accettabile. Ma non per molto.

Nel febbraio 1995, l'università di Helsinki subì un attacco di tipo password-sniffing: un aggressore aveva compromesso un router nella rete universitaria e stava intercettando le connessioni Telnet, raccogliendo credenziali in chiaro. Tatu Ylonen, ricercatore finlandese di sicurezza informatica allora all'Università di Helsinki, decise di risolvere il problema alla radice. Nel giro di pochi mesi scrisse la prima versione di SSH, che chiamò SSH-1. Lo rilasciò gratuitamente in luglio 1995 e la risposta fu immediata: in pochi mesi decine di migliaia di installazioni in tutto il mondo.

Ylonen fondò SSH Communications Security nel 1995 per commercializzare il protocollo. Nel 1999, la versione libera di SSH-1 era ancora disponibile ma la progressiva commercializzazione spinse la community open source a sviluppare OpenSSH, una reimplementazione completamente open source nata nel contesto del progetto OpenBSD. OpenSSH è oggi l'implementazione di SSH più diffusa al mondo, inclusa di default in praticamente tutte le distribuzioni Linux, macOS, e da Windows 10 in poi anche su Windows.

SSH-1 vs SSH-2: le differenze fondamentali

Il protocollo originale SSH-1 fu successivamente analizzato e trovato con diversi problemi di sicurezza: vulnerabilità nell'algoritmo di integrità dei messaggi (CRC-32), problemi nella gestione delle chiavi di sessione che permettevano attacchi di tipo man-in-the-middle in alcune circostanze, e una struttura monolitica che rendeva difficile estendere il protocollo.

SSH-2, standardizzato come RFC nel 2006 (ma disponibile dal 1996), risolve tutti questi problemi con un'architettura completamente ridisegnata e più modulare:

SSH-1 è oggi considerato deprecato e disabilitato di default da OpenSSH dalla versione 7.0 (2015). Qualsiasi sistema ancora configurato per accettare SSH-1 va considerato insicuro.

L'handshake SSH: cosa succede quando ci si connette

Quando digiti ssh [email protected], si avvia una sequenza precisa di operazioni:

1. TCP connection: Il client SSH apre una connessione TCP alla porta 22 del server (o altra porta se configurata diversamente).

2. Protocol negotiation: Client e server si scambiano le versioni del protocollo supportate. Il server risponde con un banner che include la versione SSH e la versione del software (es. SSH-2.0-OpenSSH_9.3).

3. Algoritm negotiation (KEX init): Client e server si scambiano liste di algoritmi supportati per: scambio di chiavi (Key Exchange), cifratura simmetrica della sessione, MAC (integrità), compressione. Il primo algoritmo in comune nelle rispettive liste preferite viene scelto.

4. Key Exchange (Diffie-Hellman): Questo è il cuore della sicurezza di SSH. Client e server eseguono un protocollo di scambio di chiavi che permette di stabilire un segreto condiviso senza che questo venga mai trasmesso sulla rete. L'algoritmo più comune è Curve25519 (ECDH), che ha sostituito il classico Diffie-Hellman su gruppi modulari per maggiore sicurezza e velocità.

5. Host key verification: Il server dimostra la propria identità firmando parte dello scambio con la propria chiave privata host. Il client verifica questa firma usando la chiave pubblica del server, che dovrebbe già essere nel file ~/.ssh/known_hosts. Se è la prima connessione, il client chiede conferma all'utente (il famoso "The authenticity of host can't be established...").

6. Symmetric encryption begins: Dall'output del key exchange, vengono derivate chiavi simmetriche per la cifratura (AES-CTR, ChaCha20-Poly1305) e per il MAC. Da questo punto in poi tutta la comunicazione è cifrata.

7. User authentication: Il client si autentica al server usando uno dei metodi disponibili: password, chiave pubblica, GSSAPI/Kerberos, ecc.

Diffie-Hellman: lo scambio di chiavi spiegato

Lo scambio di chiavi Diffie-Hellman (e le sue varianti moderne come ECDH su Curve25519) risolve un problema apparentemente impossibile: come possono due parti stabilire un segreto comune su un canale completamente pubblico, senza che eventuali intercettatori possano scoprirlo?

L'intuizione di base si può spiegare con l'analogia dei colori. Immagina che client e server partano entrambi con un colore pubblico comune (es. giallo). Ognuno sceglie un colore segreto che non rivela mai (es. il client sceglie rosso, il server azzurro). Ognuno mescola il proprio colore segreto con quello pubblico e manda il risultato all'altro: il client manda "giallo+rosso=arancione", il server manda "giallo+azzurro=verdino". Poi ognuno aggiunge il proprio segreto al colore ricevuto: il client fa "arancione+rosso=arancione-rosso-giallo", il server fa "verdino+azzurro=azzurro-giallo-rosso". Il risultato finale è identico, ma un intercettatore che vede solo arancione e verdino non può risalire ai colori segreti originali senza risolvere un problema computazionalmente intrattabile.

In matematica, al posto dei colori ci sono operazioni su gruppi finiti o curve ellittiche, ma il principio è lo stesso. La sicurezza dipende dalla difficoltà computazionale del problema del logaritmo discreto.

Autenticazione con password vs chiavi pubbliche

SSH supporta diversi metodi di autenticazione utente. L'autenticazione con password è la più intuitiva ma anche la meno sicura: la password viene cifrata e trasmessa al server, che la verifica contro il proprio database. I problemi sono due: le password possono essere deboli (soggette a brute force), e anche una password strong è a rischio se il server viene compromesso e i hash rubati.

L'autenticazione con chiavi pubbliche è molto più sicura e, una volta configurata, anche più comoda (non si digita la password a ogni connessione). Funziona così:

ssh-keygen: generare chiavi moderne

Il comando per generare una coppia di chiavi SSH è ssh-keygen. L'algoritmo raccomandato oggi è Ed25519, basato sulla curva ellittica Edwards-curve Digital Signature Algorithm. È più sicuro di RSA-2048, produce chiavi molto più corte (256 bit vs 2048-4096 bit), e le operazioni crittografiche sono più veloci.

ssh-keygen -t ed25519 -C "commento identificativo"

Per chi deve interoperare con sistemi legacy che non supportano Ed25519, RSA da 4096 bit è ancora accettabile:

ssh-keygen -t rsa -b 4096 -C "commento"

Importantissimo: la chiave privata dovrebbe sempre essere protetta da una passphrase. In questo modo, anche se qualcuno ruba il file della chiave privata, non può usarla senza conoscere la passphrase. La passphrase cifra la chiave privata con AES-256 prima di salvarla su disco.

La chiave pubblica viene copiata sul server con:

ssh-copy-id -i ~/.ssh/id_ed25519.pub utente@server

Configurazione sicura di sshd

Il file di configurazione del server SSH è /etc/ssh/sshd_config. Le impostazioni raccomandate per un server esposto a Internet:

Port forwarding: SSH come tunnel universale

Uno degli usi più potenti di SSH è il port forwarding, che trasforma SSH in un tunnel cifrato per qualsiasi protocollo TCP.

Local port forwarding (-L): Rende accessibile localmente un servizio remoto.

ssh -L 8080:database.interno:5432 [email protected]

Questo crea un tunnel per cui tutto ciò che si connette a localhost:8080 viene inoltrato, cifrato, a database.interno:5432 attraverso server.pubblico. Utile per accedere a database interni senza esporre le porte di PostgreSQL/MySQL a Internet.

Remote port forwarding (-R): Espone un servizio locale su un server remoto.

ssh -R 9090:localhost:3000 [email protected]

Chiunque si connetta a server.pubblico:9090 viene inoltrato a localhost:3000 del client. Utile per esporre temporaneamente un server di sviluppo locale senza configurare il router.

Dynamic port forwarding / SOCKS proxy (-D): Crea un proxy SOCKS5 locale che instrada tutto il traffico attraverso il server SSH.

ssh -D 1080 [email protected]

Configurando il browser per usare il proxy SOCKS5 su localhost:1080, tutta la navigazione viene instradata attraverso il server remoto, cifrata. Una VPN povera ma efficace per usi occasionali.

SCP e SFTP: trasferimento file sicuro

SSH include protocolli per il trasferimento file. SCP (Secure Copy Protocol) è il modo più semplice:

scp file.txt utente@server:/home/utente/

scp -r /cartella/ utente@server:/destinazione/

SCP è semplice ma limitato: non supporta la ripresa dei trasferimenti interrotti e usa lo stesso canale del protocollo SSH per tutto. SFTP (SSH File Transfer Protocol) è più robusto: supporta ripresa dei trasferimenti, operazioni sui file (rinomina, elimina, crea directory), e può essere montato come filesystem con strumenti come sshfs.

Per trasferimenti di grandi quantità di dati, rsync over SSH è la soluzione più efficiente:

rsync -avz --progress /locale/ utente@server:/remoto/

Rsync trasferisce solo le differenze tra i file locali e remoti, rendendo i backup incrementali estremamente veloci.

SSH Agent: gestire le passphrase comodamente

L'SSH agent è un demone in background che tiene in memoria le chiavi private decifrate per la sessione corrente. Invece di digitare la passphrase a ogni connessione, la si digita una volta all'avvio dell'agent:

eval $(ssh-agent -s)
ssh-add ~/.ssh/id_ed25519

L'agent forwarding (ssh -A) permette di usare le chiavi locali anche quando si è connessi a un server intermedio per saltare a un terzo server, senza copiare le chiavi private sui server intermedi. Va usato con cautela su server non fidati, poiché un root del server potrebbe teoricamente accedere all'agent e usare le chiavi.

Il file ~/.ssh/config: semplificare le connessioni

Il file di configurazione client SSH (~/.ssh/config) permette di definire alias e opzioni per i server a cui ci si connette frequentemente:

Host produzione
    HostName server.miodominio.com
    User amministratore
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_produzione
    ForwardAgent no

Host jumphost
    HostName bastion.azienda.com
    User mario

Host server-interno
    HostName 192.168.1.50
    User ubuntu
    ProxyJump jumphost

Con questa configurazione, ssh produzione si connette automaticamente con le opzioni corrette. Il campo ProxyJump è particolarmente utile per accedere a server interni attraverso un bastion host, senza dover manualmente fare ssh a due passaggi.

Fail2ban: proteggere SSH dagli attacchi brute-force

Qualsiasi server SSH esposto a Internet viene colpito da scanner automatici che tentano centinaia di combinazioni username/password al minuto. Con PasswordAuthentication no questi attacchi sono inefficaci, ma generano comunque rumore nei log e consumano risorse.

Fail2ban monitora i log di SSH e blocca automaticamente gli IP che superano una soglia di tentativi falliti con regole iptables. La configurazione di base in /etc/fail2ban/jail.local:

[sshd]
enabled = true
maxretry = 3
bantime = 3600
findtime = 600

Questo blocca per 1 ora qualsiasi IP che fallisce 3 autenticazioni in 10 minuti.

SSH in Git, CI/CD e IoT

SSH è la spina dorsale di molti ecosistemi tecnici oltre al semplice accesso remoto. GitHub, GitLab e Gitea usano SSH come protocollo primario per push e pull di repository: la chiave pubblica dell'utente viene aggiunta all'account, e il client Git usa la chiave privata per autenticarsi al server Git.

Nei sistemi CI/CD (GitHub Actions, GitLab CI, Jenkins), SSH viene usato per il deployment: il pipeline di build usa chiavi SSH per copiare i file compilati sul server di produzione via SCP/rsync, o per eseguire comandi di deployment remoti.

Nel mondo IoT e embedded, SSH è il modo standard per accedere a Raspberry Pi, router OpenWrt, NAS, e qualsiasi dispositivo Linux. La semplicità di SSH — client disponibile su qualsiasi sistema Unix, implementazione minima possibile in dropbear per sistemi embedded — lo rende insostituibile.

Dopo trent'anni, SSH rimane uno dei protocolli di rete più robusti, sicuri e duraturi mai progettati. È il risultato di una buona crittografia, di un'interfaccia semplice e di un'implementazione open source di alta qualità che ha beneficiato di decenni di audit e miglioramenti. È difficile immaginare un sostituto nel prossimo futuro.