Accesso in SSH/SFTP ad un host remoto tramite PHP con scambio di chiavi

L’accesso in SSH/SFTP ad un host remoto tramite PHP sembra una faccenda abbastanza semplice, ma poi finisce per non funzionare.

Il motivo è che la soluzione proposta spesso nei forum è quella di eseguire l’autenticazione tramite ssh2_auth_password() , che emula l’autenticazione da tastiera.

Ma spesso non funziona, perché molti server SSH sono configurati con

 

Ed è giusto. Quando facciamo l’autenticazione da tastiera le credenziali vengono inviate in modo cifrato attraverso PAM e SSH stesso. La PasswordAuthentication da sola, invece, invia la password in chiaro indebolendo il sistema.

Poiché stiamo parlando della configurazione del server, piegare un server a questa vulnerabilità solo per far girare una certa applicazione non è una buona idea.

Conviene usare l’autenticazione tramite chiavi e la funzione PHP ssh2_auth_pubkey_file() .

L’autenticazione tramite chiavi

L’autenticazione tramite chiavi è ben raccontata in giro. A me piace la pagina Keychain del wiki di Gentoo, ma ci sono moltissime altre guide.

L’idea (molto molto brevemente) è che nell’host dove viene eseguito il client viene generata una coppia di chiavi, una pubblica e una privata, che consentono di cifrare e decifrare i messaggi.

Basta copiare la chiave pubblica locale nel lato server (e in particolare nella home dell’utente remoto) per garantire le comunicazioni.

Ad ulteriore sicurezza, la chiave privata viene protetta da una passphrase. Assomiglia ad una password nell’uso, ma la differenza sostanziale è che viene richiesta localmente per accedere alla chiave privata e non viaggia nella rete.

Nel nostro caso dovremo curare due aspetti particolari:

  1. Se il PHP viene eseguito attraverso Apache, creare le chiavi per l’utente che esegue Apache (diciamo apache ), che è un utente di sistema e per il quale non abbiamo una home e non riusciremo a fare su - apache .
  2. Gestire le chiavi con il PHP

Creare la coppia di chiavi per l’utente apache

Agiremo come  root  nell’host locale.
Per intenderci, chiameremo  client.mydomain  il client e  server.theirdomain  il server. Nel server vogliamo autenticarci con l’utente jhonny .

Per prima cosa, creiamo una directory per la conservazione delle chiavi:

 

Poi generiamo le chiavi, con un piccolo accorgimento rispetto alle guide:

 

L’accorgimento è l’ultima opzione (-C), che serve a modificare il “comment”, cioè l’ultima parte della chiave pubblica.

Dovremmo avere il seguente dialogo (attenzione, la posizione dei file NON è quella di default):

 

Due osservazioni.
La prima è che, contrariamente al suggerimento, abbiamo richiesto di depositare le chiavi nella directory creata poco prima.
La seconda è che non è il caso di fare economia di passphrase: inseriamo una passphrase robusta, tanto non dovremo digitarla se non al momento di inserire i parametri nel programma PHP.

Una nota aggiunta successivamente: in alcuni scenari – ad esempio lavorando con Debian Wheezy e PHP 5.4.4-14+deb7u7 – è emersa la necessità di lavorare con chiavi private cifrate. L’argomento è trattato nell’ultimo paragrafo.

Ora dobbiamo gestire proprietà e permessi del materiale appena creato.

Il materiale appartiene ad apache:apache :

 

E non deve essere letto da tutti:

 

L’ultimo passaggio è copiare la chiave pubblica (attenzione) nella home dell’utente con cui vorremo autenticarci, in server.theirdomain .

 

L’autenticazione in questa fase avverrà nel solito modo. Se la directory  ~/.ssh  non esiste in server.theirdomain , spostiamoci prima lì e creiamola, con permessi 0700 .

Il programma in PHP

A questo punto il programma in PHP che esegue la connessione e si autentica è il seguente.

 

Dovrebbe funzionare e mostrare il contenuto della propria home remota.

Una nota aggiunta successivamente: qualora non funzioni, potrebbe essere per le ragioni indicate nell’ultimo paragrafo.

Considerazioni

È utile. A me vengono in mente diversi utilizzi, quali eseguire comandi remoti e trasferire file in modo affidabile con SFTP.

Ma è utile anche se usato nello stesso sistema locale. Sì, parlo di fare connessioni SSH a localhost. In questo modo, infatti, si aggira il mai troppo ben risolto problema di far agire Apache come utente diverso da apache , ad esempio per manipolare i file locali.

Il bug 58573 del PHP

Aggiungo questo paragrafo successivamente, dopo essermi imbattuto nel bug usando il Raspberry PI.

A causa del bug 58573, in quasi nessun caso PHP riesce a utilizzare la chiave privata se è stata generata con  libssh2  compilato con il supporto libgcrypt . È uno scenario per niente raro, che si verifica normalmente in Debian Wheezy e nelle sue derivate (Ubuntu, Mint, Raspbian, eccetera) e ovviamente anche in altri casi.

La soluzione può essere ricompilare  libssh2  con il supporto openssl , ma c’è anche un workaround (a cui si accenna in fondo al bug report) che risolve tutto. C’è un caso, infatti, in cui il PHP riesce a gestire la cifratura della chiave privata nonostante il bug: la cifratura PEM.

Il grosso delle differenze è nella preparazione delle chiavi. Si usa necessariamente RSA invece che DSA.

 

Poi si genera la chiave cifrata.

 

Infine, nel programma in PHP, si utilizza la chiave cifrata appena costruita.


 

Et voilà.

Leave a Comment

Your email address will not be published.

1 Trackback

  1. Informatica: equivoci semplici, soprattutto negli ambienti di lavoro della PA | Sergio VaccaroSergio Vaccaro (Pingback)
Analisi degli accessi a www.istat.it
×
', 'auto'); ga('require', 'displayfeatures'); ga('set', 'forceSSL', true); ga('send', 'pageview');