# Secure Shell

In informatica e telecomunicazioni Il Secure Shell Protocol (SSH) è un protocollo di rete crittografico che permette di stabilire una sessione remota cifrata tramite interfaccia a riga di comando con un altro host di una rete informatica. È il protocollo che ha sostituito l'analogo, ma non sicuro, Telnet.

## Descrizione

Il client SSH ha un'interfaccia a riga di comando simile a quella di telnet e rlogin, ma l'intera comunicazione (ovvero sia l'autenticazione - mutua - che la sessione di lavoro) avviene in maniera cifrata. Per questo motivo, SSH è diventato uno standard di fatto per l'amministrazione remota di sistemi UNIX e di dispositivi di rete, rendendo obsoleto il protocollo telnet, giudicato troppo pericoloso per la sua mancanza di protezione contro le intercettazioni.
Il client ed il server SSH sono installati o installabili su molte versioni di UNIX, GNU/Linux, macOS e Microsoft Windows. Inoltre è disponibile come strumento di amministrazione su alcuni apparati di rete. La IANA (Internet Assigned Numbers Authority) ha assegnato al servizio SSH la porta 22 TCP e UDP, anche se è comunque possibile implementare il servizio SSH su altre porte non definite dalla IANA.
Il comando su sistemi UNIX-like è il seguente:
La prima versione dell'SSH era completamente open Source, mentre la seconda è diventata commerciale; esiste comunque una versione libera detta OpenSSH che si basa sulla prima versione, ma che fornisce supporto alla seconda versione.

## Architettura del protocollo

Il protocollo SSH si basa su un'architettura rappresentabile in tre distinti livelli: Transport Layer Protocol, User Authentication Protocol e Connection Layer Protocol. La divisione in tre livelli indipendenti garantisce un'estrema flessibilità del protocollo: l'indipendenza logica dei livelli permette di modificare la configurazione della connessione senza dover modificare i livelli superiori o inferiori del protocollo, per esempio si può modificare il protocollo di compressione delle informazioni senza dover cambiare il protocollo di cifratura o di autenticazione del sistema.
È importante specificare che i livelli sopra citati non hanno alcuna relazione con i livelli dello standard ISO/OSI essendo livelli interni al protocollo SSH che a sua volta è posizionabile subito sopra al livello di trasporto ISO/OSI. Di fatto i livelli interni al protocollo SSH coprono gli ultimi tre livelli della pila ISO/OSI applicando un'organizzazione diversa da quella prevista dallo standard per le reti.

### Transport Layer Protocol

Il Transport Layer Protocol è il primo dei tre livelli del protocollo SSH, in esso sono contenuti tutti i protocolli e le procedure utilizzate nell'instaurazione e creazione del canale cifrato di comunicazione client-server. All'interno del Transport Layer avviene l'autenticazione del server, lo scambio delle chiavi, la cifratura, la compressione e il controllo d'integrità dei pacchetti. Il livello comprende in parte il livello di sessione e in parte il livello di presentazione dello standard ISO/OSI. La connessione creata sfrutta normalmente il protocollo TCP/IP per la comunicazione al livello di rete e di trasporto ma è teoricamente indipendente da esso. Nel Transport Layer viene effettuato il controllo dell'integrità dei pacchetti ma non vengono gestiti i casi in cui i pacchetti della connessione vengano persi, in tali casi la sessione viene terminata e deve essere ristabilita completamente. Per tali motivi i protocolli di trasporto orientati alla connessione come il TCP sono fortemente consigliati per impedire la perdita di pacchetti e la chiusura della connessione.

#### Scambio delle chiavi

Dopo la definizione degli algoritmi da utilizzare nella connessione avviene uno dei passi più importanti nell'instaurazione del canale sicuro di comunicazione: lo scambio delle chiavi. Per poter garantire la sicurezza e la privatezza della comunicazione è indispensabile stabilire degli algoritmi di scambio delle chiavi sicuri, una falla di sicurezza nello scambio delle chiavi comprometterebbe l'intera connessione. La negoziazione delle chiavi avviene all'inizio di ogni connessione, per garantire maggiore sicurezza le chiavi vengono generalmente rinegoziate ogni ora o ogni gigabyte di dati transitato nella connessione.
Gli algoritmi di scambio di chiavi più utilizzati sono:
* diffie-hellman-group1-sha1
* diffie-hellman-group14-sha1
I due algoritmi utilizzati sono variazioni dell'algoritmo di scambio di chiavi Diffie-Hellman in cui è stato aggiunto un sistema di certificazione del server mediante un host key. Osservando le stringhe identificatrici degli algoritmi è possibile dedurre che esse variano solo per il termine groupX, tale termine definisce il gruppo utilizzato nella definizione dei parametri dell'algoritmo Diffie-Hellman, tali gruppi sono documentati all'interno del RFC3526.
L'algoritmo Diffie-Hellman è stato certificato come uno dei più sicuri metodi di scambio di chiavi su un canale di comunicazione non sicuro ed è tra gli algoritmi più utilizzati al mondo. A causa dell'elevato numero di calcoli necessari per lo scambio di chiavi Diffie-Hellman è possibile utilizzare nei sistemi più vecchi e con meno potenza di calcolo l'algoritmo RSA egualmente sicuro ma meno esigente in termini di potenza di calcolo.

#### Autenticazione del server

L'autenticazione del server serve ad evitare che un utente maligno "impersonifichi" il server, facendosi fornire le credenziali dell'utente (spoofing da attacco man in the middle). A questo scopo, per ciascun server viene generata una coppia di chiavi asimmetriche. La chiave privata rimane sul server. La chiave pubblica deve essere conosciuta dal client, il client può ottenere la chiave di un server utilizzando archivi pubblici delle chiavi disponibili sul web o ricevendola direttamente dal server durante la prima connessione.
L'autenticazione avviene durante lo scambio di chiavi Diffie-Hellman, il server crea un messaggio cifrato con la propria chiave privata e la invia al client, il client la decifra con la chiave pubblica del server verificando l'identità del server, se la decifrazione del messaggio avviene correttamente il client procede con l'instaurazione della connessione, in caso contrario interrompe la procedura. Dato che solo il server dovrebbe essere a conoscenza della chiave privata il client è in grado di determinare l'identità del server con cui sta comunicando.

#### Crittografia della connessione

Definita una chiave segreta conosciuta esclusivamente dal client e dal server è possibile utilizzare un protocollo di crittografia simmetrica per cifrare la comunicazione tra client e server.
Un algoritmo di crittografia simmetrico permette di utilizzare un'unica chiave per cifrare e decifrare delle informazioni. In un algoritmo a chiave simmetrica la chiave condivisa deve essere definita prima dell'inizializzazione della connessione utilizzando un metodo di comunicazione della chiave sicuro che nell'SSH avviene utilizzando l'algoritmo Diffie-Hellman. Gli algoritmi a chiave simmetrica garantiscono un alto standard di sicurezza e un basso costo in termini di potenza di calcolo (a differenza degli algoritmi a chiave asimmetrica come l'algoritmo RSA).
La lista degli algoritmi simmetrici utilizzabili dal protocollo SSH comprende:
* 3des-cbc
* blowfish-cbc
* twofish256-cbc
* twofish-cbc
* twofish192-cbc
* twofish128-cbc
* aes256-cbc
* aes192-cbc
* aes128-cbc
* serpent256-cbc
* serpent192-cbc
* serpent128-cbc
* arcfour
* idea-cbc
* cast128-cbc
Gli algoritmi più utilizzati sono l'AES e il 3DES presenti su praticamente tutti i computer.
È possibile utilizzare un algoritmo di crittografia nullo che di fatto non esegue alcuna operazione di cifratura, tale scelta è fortemente sconsigliata in quanto renderebbe l'intera comunicazione insicura.
Dopo aver stabilito i protocolli da utilizzare e dopo aver effettuato lo scambio di chiavi mediante il protocollo Diffie-Hellman è possibile instaurare la connessione criptata con l'algoritmo a chiave simmetrica precedentemente definito.

#### Compressione delle informazioni

Il protocollo SSH permette di applicare algoritmi di compressione delle informazioni al flusso di dati passante nella connessione. Attualmente è supportata la compressione mediante la libreria zlib.

#### Integrità dei pacchetti

Il controllo di integrità delle informazioni è un processo che permette di verificare che i dati contenuti in un pacchetto ricevuto da uno dei due host della connessione corrispondano ai dati inviati dall'altra macchina. Il processo di controllo delle informazioni permette di individuare eventuali errori in fase di invio e soprattutto permette di individuare eventuali attacchi replay da parte di computer esterni alla comunicazione.
Gli algoritmi di MAC (Message Authentication Code) utilizzabili nel protocollo SSH sono:
* hmac-sha1
* hmac-sha1-96
* hmac-md5
* hmac-md5-96
Il processo di controllo d'integrità è consigliato ma non obbligatorio in una connessione SSH.
Il controllo d'integrità dei pacchetti viene effettuato dopo la definizione della chiave segreta della connessione, prima non è possibile effettuare un controllo d'integrità.

### User Authentication Protocol

Dopo aver creato un canale di comunicazione sicuro il protocollo ssh prevede l'autenticazione dell'utente mediante metodi definiti nello User Authentication Protocol. Questo livello dell'architettura del protocollo SSH comprende le operazioni previste dallo standard ISO/OSI per il livello di sessione.

#### Autenticazione via chiave pubblica

L'autenticazione a chiave pubblica è il metodo di autenticazione più sicuro implementato nel protocollo SSH e deve essere sempre disponibile in ogni server. Questo metodo di autenticazione è basato sulla crittografia asimmetrica. L'algoritmo di crittografia asimmetrica più utilizzato per la generazione delle chiavi è l'RSA.

##### Procedura
###### Generazione e trasferimento delle chiavi

Per autenticarsi il client genera una coppia di chiavi pubblica/privata utilizzando un algoritmo di crittografia asimmetrico supportato dal protocollo SSH mediante il comando ssh-keygen. Generate le chiavi l'utente deve trasferire la propria chiave pubblica sul server in cui viene generalmente memorizzata in un apposito file nella home directory dell'utente nel server; la chiave privata viene conservata sul client e non deve essere divulgata, per garantire una maggiore sicurezza è possibile proteggere la chiave privata con una parola chiave (passphrase). L'utente può trasferire la propria chiave pubblica sul server sia mediante supporti di memorizzazione fisici che mediante il comando ssh-copy-id.

###### Autenticazione

Il server sorgente per verificare l'identità dell'utente sfrutta le particolari caratteristiche degli algoritmi di crittografia asimmetrici. Durante la fase di autenticazione il server genera una stringa casuale di 256 bit, la cifra usando la chiave pubblica dell'utente e l'algoritmo di cifratura corrispondente alla chiave e la invia al client. Il client decifra il messaggio utilizzando la propria chiave privata e invia l'hash della stringa ricevuta al server, se l'hash della stringa del client corrisponde all'hash della stringa del server l'utente viene autenticato. Solo chi possiede la chiave privata dell'utente è in grado di decifrare correttamente il messaggio cifrato del server, in questo modo il server è in grado di verificare l'identità del client.
Nell'autenticazione mediante chiavi pubbliche non viene richiesta nessuna password all'utente tranne nel caso in cui sia stata applicata una passphrase alla chiave privata.

#### Autenticazione via password

L'autenticazione via password è il metodo più semplice di autenticazione supportato dal protocollo SSH.
L'utente fornisce un nome utente ed una password, il server confronta tali dati con il database degli utenti del sistema operativo. Questo scambio avviene all'interno di un canale cifrato, per cui non è a rischio di intercettazione.
Procedura:
* A$ ⇒ B: SSH_MSG_USERAUTH_REQUEST, pappy, ssh-userauth, keyboard-interactive
* B$ ⇒ A: SSH_MSG_USERAUTH_INFO_REQUEST, pappy, password-authentication, 1, "Enter Password"
* A$ ⇒ B: SSH_MSG_USERAUTH_INFO_RESPONSE, 1, "love"
* B$ ⇒ A: SSH_MSG_USERAUTH_SUCCESS.
Per prevenire attacchi brute force si può utilizzare un tool DenyHosts o Fail2ban.

### Connection Layer Protocol

Il Connection Layer è il livello più alto del protocollo SSH, permette l'instaurazione di terminali interattivi, esecuzione di comandi remoti, il forward di connessioni e il forward di applicazioni grafiche X11. Il Connection Layer gestisce tali funzionalità utilizzando canali multipli di comunicazione passanti per lo stesso tunnel criptato del Transport Layer.

#### I canali

Ogni terminale interattivo aperto e ogni connessione inoltrata attraverso la connessione SSH può occupare un canale di comunicazione. Essendo possibile l'instaurazione di canali multipli ogni canale possiede un numero identificativo, tale numero viene utilizzato per distinguere pacchetti appartenenti a canali diversi permettendo all'applicativo SSH di ricostruire le diverse comunicazioni aperte attraverso il tunnel criptato. L'apertura di un canale avviene quando entrambe le parti concordano la sua creazione, se una delle due parti rifiuta, il canale non viene creato. Fintanto che uno degli host non ha ancora confermato l'apertura del canale nessun pacchetto è autorizzato ad utilizzare tale canale.

#### Port forwarding

Grazie all'estrema flessibilità del protocollo SSH è possibile realizzare tunnel criptati in grado di trasportare sessioni TCP arbitrarie all'interno della connessione criptata, permettendo di proteggere da intercettazione protocolli non sicuri, o di aggirare limitazioni di routing.
Questa funzionalità è detta port forwarding, e permette di aprire un socket TCP sul client SSH (local port forwarding) o sul server (remote port forwarding). Le connessioni ricevute su questa porta vengono inoltrate dall'altro capo della connessione SSH, verso un host e una porta specificata.
Ad esempio, con questo comando ci si collega ad host1, inoltrando la porta 10022 della macchina in cui lanciamo il client ssh alla porta 22 di host2 attraverso un canale sicuro tra client e host1:
Mentre questa connessione è attiva, collegandosi alla porta 10022 del client si viene rediretti verso la porta 22 di host2.

##### Esempio di uso del port forwarding

Il port forwarding è utile ad esempio per fare assistenza remota a macchine prive di un sistema di gestione remota sicuro. È possibile creare un tunnel sicuro tra una porta del client e una porta del server remoto o di qualsiasi terza macchina dietro al server remoto, a patto che la macchina server abbia abilitato il forwarding. Questo è normalmente possibile senza installare nessun pacchetto aggiuntivo.
Ad esempio, nel seguente scenario
Se vogliamo utilizzare un desktop remoto sulla terza macchina basta che ci connettiamo al server ssh includendo un tunnel tra una porta locale della macchina dove lavoriamo e la porta 3389 della TERZA MACCHINA. Dopo di che basterà avviare il client RDP e connettersi a localhost:(porta scelta).
Il client ssh locale stabilirà una connessione criptata con il server, creerà un tunnel all'interno di questa connessione criptata, ed invierà la connessione RDP su questo tunnel. Il server a sua volta stabilirà una normale sessione TCP con la terza macchina sulla porta richiesta.
Come risultato, il client RDP verrà messo in comunicazione con la terza macchina. La connessione tra ssh server e terza macchina non sarà criptata, per cui è opportuno che la comunicazione tra queste due macchine non sia a rischio di intercettazione. La terza macchina vedrà la connessione TCP provenire dal server ssh invece che dal client.

#### X forwarding

Il port forwarding è utile anche per trasportare applicazioni X Window attraverso una connessione SSH. SSH imposta anche automaticamente le opportune variabili d'ambiente, in modo che le applicazioni X lanciate da un terminale remoto vengano visualizzate sul display da cui è stata avviata la connessione.
L'X forwarding dal lato client deve essere abilitato passando l'opzione "-X" mentre dal lato server va modificato il file di configurazione /etc/ssh/sshd_config abilitando la direttiva X11Forwarding (ricordatevi di riavviare il server una volta apportata la modifica al file di configurazione).