<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>otp &amp;mdash; Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/tag:otp</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Thu, 30 Apr 2026 09:57:42 +0000</pubDate>
    <item>
      <title>Abilitare la 2FA in ssh</title>
      <link>https://noblogo.org/aytin/abilitare-la-2fa-in-ssh</link>
      <description>&lt;![CDATA[lock&#xA;smalliFonte:  Foto di Life Of Pix da a href=&#34;https://www.pexels.com/it-it/foto/lucchetto-in-metallo-color-ottone-con-catena-4291/&#34;Pexels.com/a/i/small&#xA;Cosa si intende per 2FA&#xA;&#xA;Attivare la 2FA è sempre una buona pratica per mitigare attacchi di tipo brute-force.&#xA;Perché non farlo pure per ssh, soprattutto se lo si usa nel bastion host per accedere alla nostra lan?&#xA;Da letteratura, la 2FA consiste nel fornire 2 fattori di autenticazione fra:&#xA;!--more--&#xA;&#xA;qualcosa che sai (ad es. una password o un pin)&#xA;qualcosa che hai (ad es. un otp)&#xA;qualcosa che sei (ad es. un rilievo biometrico)&#xA;&#xA;Se i fattori sono più di due, si parla di Multi Factor Authentication (MFA).&#xA;&#xA;Non entro nel merito della configurazione di un servizio ssh , che non è banale. La diamo per scontata, ci concentriamo sulla parte di autenticazione.&#xA;Metodi di autenticazione&#xA;&#xA;La buona norma vorrebbe che un&#39;autenticazione su un server openssh si limitasse all&#39;autenticazione con chiave pubblica. Su alcune distro ad es. è l&#39;unica disponibile di default.&#xA;Ma non basta una buona autenticazione per garantire la sicurezza di un servizio come SSH. Occorrerebbe intervenire su ben altri aspetti perché altrimenti sarebbe come preoccuparsi della bontà della porta blindata per la nostra casa dalle pareti di cartone.&#xA;&#xA;I parametri del file di configurazione che andrò a trattare riguardano le modalità di autenticazione di ssh. La versione che sto usando su debian bullseye è la 8.4p1.&#xA;Queste sono:&#xA;&#xA;password&#xA;publickey&#xA;keyboard-interactive&#xA;gssapi-with-mic&#xA;hostbased&#xA;none&#xA;&#xA;Le prime 3 sono quelle che ci interessano sul serio.&#xA;&#xA;Con ssh posso avere:&#xA;&#xA;una 2FA (ad es. publickey + password)&#xA;una MFA (ad es. publickey (qualcosa che sei) + password (qualcosa che sai) + OTP (qualcosa che hai) , se ipotizziamo publickey, in quanto certificato digitale, assimilabile al rilievo biometrico).&#xA;&#xA;Per realizzare i due scenari c&#39;è bisogno di settare con attenzione ssh per non rischiare di lasciare voragini invece che mettere in sicurezza il servizio.&#xA;&#xA;Suppongo che ssh sia già settato come si deve, ciò che andrò a toccare sarà:&#xA;&#xA;UsePAM&#xA;  Abilita o meno l&#39;uso di PAM&#xA;ChallengeResponseAuthentication (KbdInteractiveAuthentication dalla 8.8)&#xA;  Permette di applicare lo schema Challenge-Response per l&#39;autenticazione&#xA;PublicKeyAuthentication&#xA;  Abilita o meno l&#39;autenticazione con chiave pubblica&#xA;PasswordAutentication&#xA;  Abilita o meno l&#39;autenticazione con password&#xA;AuthenticationMethods&#xA;È la lista  (l&#39;elenco precedente) dei metodi di autenticazione che vogliamo permettere.&#xA;Se gli elementi sono separati da una virgola, vuol dire che sono tutti obbligatori (per avere un&#39;autenticazione multipla per es.).&#xA;Se sono separati da uno spazio, vuol dire che sono facoltativi.&#xA;Es. publickey,password password publickey,password,keyboard-interactive. &#xA;Vuol dire che mi posso autenticare fornendo chiave e password oppure password oppure chiave+password+otp&#xA;È abbastanza chiaro che una configurazione del genere può essere molto pericolosa perché il suo livello di robustezza dipende dal suo anello più debole (la password in questo caso) che può vanificare tutti gli altri.&#xA;&#xA;Ogni modifica del file di configurazione richiederà il a id=&#34;restart&#34;restart/a del servizio ssh.&#xA;systemctl restart sshd.service&#xA;PAM&#xA;&#xA;Com&#39;è noto, e banalizzando molto, PAM è un sottosistema gnu/linux che fornisce un livello di astrazione a quelle applicazioni, come ssh, che richiedono autenticazione. In questo modo le applicazioni non hanno bisogno di implementarle esplicitamente e, volendo, possono estendere i propri schemi di autenticazione aumentandone la complessità in maniera relativamente semplice.&#xA;&#xA;PAM, insieme ad una autenticazione di tipo challenge-response, ci permetterà di ottenere un&#39;autenticazione multipla.&#xA;Scenario 1: Configurazione sicura (chiave pubblica)&#xA;&#xA;In molti contesti si preferisce abilitare la sola autenticazione con chiave pubblica, proprio per evitare possibili falle. Niente PAM in questo caso ma solo configurazione ssh:&#xA;...&#xA;UsePAM=no&#xA;ChallengeResponseAuthentication=no&#xA;PublicKeyAuthentication=yes&#xA;PasswordAuthentication=no&#xA;AuthenticationMethods=publickey&#xA;...&#xA;PAM viene disabilitato perché scegliamo di non affidarci a librerie di autenticazione esterne. Inoltre, in casi estremi, si può pensare che un aggiornamento di PAM possa rompere la compatibilità con qualche libreria invalidando o indebolendo il processo di autenticazione.&#xA;&#xA;Di conseguenza, niente autenticazione di tipo challenge-response, niente autenticazione con password.&#xA;&#xA;Attiviamo solo la PublicKeyAuthentication rafforzando la scelta in AuthenticationMethods dove impostiamo come unico metodo valido publickey. Infine, a href=&#34;#restart&#34;riavviamo/a il servizio.&#xA;&#xA;L&#39;unico modo per accedere al server ssh è possedere una chiave (o un certificato) valida.&#xA;&#xA;Scenario 2: 2FA (chiave pubblica + password)&#xA;&#xA;Facciamo un passo in più è facciamo in modo che l&#39;accesso al server sia consentito solo a chi possiede sia chiave che password.&#xA;&#xA;...&#xA;UsePAM=no&#xA;ChallengeResponseAuthentication=no&#xA;PublicKeyAuthentication=yes&#xA;PasswordAuthentication=yes&#xA;AuthenticationMethods=publickey,password&#xA;...&#xA;Oltre che specificare il tipo di autenticazione (PublickeyAutentication e PasswordAuthentication), imponiamo che il metodo sia quello di esibire entrambe le credenziali.&#xA;&#xA;Non impostando AutenticationMethods, varrebbe il default che prevede uno fra password, publickey o keyboard-interactive.&#xA;&#xA;L&#39;ultimo sarebbe comunque inutile in questo caso, visto che pam e challenge-response sono disabilitati. Ma non avremmo ottenuto ciò che ci eravamo prefissati.&#xA;&#xA;Una a id=&#34;scenario-2-pam&#34;configurazione analoga/a è la seguente:&#xA;...&#xA;UsePAM=yes&#xA;ChallengeResponseAuthentication=yes&#xA;PublicKeyAuthentication=yes&#xA;PasswordAuthentication=no&#xA;AuthenticationMethods=publickey,keyboard-interactive&#xA;...&#xA;a href=&#34;#restart&#34;Riavviamo/a ssh e la nuova autenticazione sarà disponibile come al solito.&#xA;&#xA;È un esempio di come posso usare PAM per rimpiazzare la PasswordAuthentication nativa.&#xA;Con una combinazione di PAM e autenticazione challenge-response, attraverso il metodo esplicito keyboard-interactive, l&#39;applicazione autenticherà con un&#39;unica sfida che è la richiesta di password.&#xA;&#xA;Con PAM posso aggiungere altro, ad es. l&#39;otp, come vedremo nel 3° scenario.&#xA;Scenario 3: MFA (chiave pubblica + password + otp)&#xA;&#xA;Lasciamo inalterata la configurazione ssh a href=&#34;#scenario-2-pam&#34;dello scenario 2/a, quella che fa uso di pam.&#xA;Bisogna innanzittutto installare il plugin per l&#39;otp.&#xA;&#xA;Sistemi debian-based:&#xA;apt install libpam-google-authenticator&#xA;&#xA;Sistemi rpm-based:&#xA;dnf install google-authenticator&#xA;&#xA;Per completezza, giusto perché lo uso, MacOS (via brew):&#xA;brew install google-authenticator-libpam&#xA;&#xA;Dopo l&#39;installazione, il generatore otp va inizializzato lanciando l&#39;eseguibile che porrà una serie di domande:&#xA;&#xA;generare i token su base temporale: Y/N (consigliato Y)&#xA;creare un file di configurazione nella home dell&#39;utente: Y/N (consigliato Y)&#xA;disabilitare la possibilità che un token possa essere usato più volte: Y/N (consigliato Y)&#xA;(semplificando) aumentare la finestra temporale di generazione dei token (default 30s): Y/N (consigliato N, a meno che la connessione fra client e server non sia ESTREMAMENTE lenta)&#xA;abilitare il rate-limit per scoraggiare attacchi di brute-force: Y/N (consigliato Y)&#xA;&#xA;A seguire, verrà mostrato sia il qr-code (per il caricamento automatico della chiave su un authenticator come FreeOtp+) che la chiave privata (se si vuole procedere con la configurazione manuale dell&#39;authenticator o dello script visto tempo fa), necessari per la fornitura del primo codice che inizializza il processo.&#xA;&#xA;Infine configuriamo PAM per sshd.&#xA;In /etc/pam.d/sshd dobbiamo imporre che il processo di autorizzazione includa obbligatoriamente l&#39;otp. Lo faremo aggiungendo una riga contenente il riferimento alla libreria che lo  implementa:&#xA;auth required pamgoogleauthenticator.so&#xA;Il solito a href=&#34;#restart&#34;riavvio/a di ssh (alcuni consigliano anche di fare il reboot della macchina per inizializzare correttamente il generatore di otp ma non ho trovato una giustificazione convincente del perché) completa il lavoro.&#xA;&#xA;Per autenticarsi sul server ssh ora serviranno:&#xA;&#xA;chiave pubblica&#xA;password&#xA;otp&#xA;&#xA;Scenario 3bis: 2FA (chiave pubblica + otp)&#xA;&#xA;Se invece volessi avere una 2FA come a href=&#34;#scenario-2-pam&#34;nello scenario 2/a, ma con otp invece che con password, posso procedere così.&#xA;Si lascia inalterata la configurazione ssh e si commenta una riga dalla configurazione di PAM:&#xA;&#xA;Su /etc/pam.d/sshd commentare la seguente riga così:&#xA;...&#xA;@include common-auth&#xA;...&#xA;In questo modo, si elimina la richiesta della password utente dalle &#34;sfide&#34; della challenge-response e rimane la sola richiesta otp.&#xA;Tips&#xA;&#xA;Attenzione quando si gioca con i metodi di autenticazione ssh.&#xA;Ci sono buone possibilità che vi autoescludiate dal vostro server.&#xA;Basta avere keyboard-interactive (che implica un&#39;autenticazione di tipo challenge-response) fra i metodi di autenticazione obbligatori e pam disattivato. &#xA;Ecco un esempio:&#xA;...&#xA;usePAM no &#xA;ChallengeResponseAuthentication yes&#xA;PasswordAuthentication no&#xA;PubkeyAuthentication no&#xA;AuthenticationMethods keyboard-interactive&#xA;...&#xA;Oppure, ancora più subdolo, lo scenario 3 con pam disabilitato, ossia:&#xA;configurazione ssh&#xA;...&#xA;usePAM no &#xA;ChallengeResponseAuthentication yes&#xA;PasswordAuthentication no&#xA;PubkeyAuthentication yes&#xA;AuthenticationMethods publickey,keyboard-interactive&#xA;...&#xA;In questi casi, l&#39;autenticazione fallirà con questo errore: &#34;Permission denied (keyboard-interactive)&#34;_ perché non sarà disponibile nessuna interazione da tastiera (es. una password) e noi rimarremmo chiusi irrimediabilmente fuori dal nostro server.&#xA;&#xA;#ssh #otp]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/c537ce87c-f5971d/SlPG8xNlTawi/codfAWO17f4vO48VMakyvf0xahvGEOzb453JEcpm.jpg" alt="lock">
<small><i>Fonte:  Foto di Life Of Pix da <a href="https://www.pexels.com/it-it/foto/lucchetto-in-metallo-color-ottone-con-catena-4291/" rel="nofollow">Pexels.com</a></i></small></p>

<h2 id="cosa-si-intende-per-2fa">Cosa si intende per 2FA</h2>

<p>Attivare la 2FA è sempre una buona pratica per mitigare attacchi di tipo brute-force.
Perché non farlo pure per ssh, soprattutto se lo si usa nel bastion host per accedere alla nostra lan?
Da letteratura, la <strong>2FA</strong> consiste nel fornire 2 fattori di autenticazione fra:
</p>
<ol><li>qualcosa che sai (ad es. una password o un pin)</li>
<li>qualcosa che hai (ad es. un otp)</li>
<li>qualcosa che sei (ad es. un rilievo biometrico)</li></ol>

<p>Se i fattori sono più di due, si parla di <strong>Multi Factor Authentication (MFA)</strong>.</p>

<p>Non entro nel merito della configurazione di un servizio ssh , che non è banale. La diamo per scontata, ci concentriamo sulla parte di autenticazione.</p>

<h2 id="metodi-di-autenticazione">Metodi di autenticazione</h2>

<p>La buona norma vorrebbe che un&#39;autenticazione su un server openssh si limitasse all&#39;<strong>autenticazione con chiave pubblica</strong>. Su alcune distro ad es. è l&#39;unica disponibile di default.
Ma non basta una buona autenticazione per garantire la sicurezza di un servizio come SSH. Occorrerebbe intervenire su ben altri aspetti perché altrimenti sarebbe come preoccuparsi della bontà della porta blindata per la nostra casa dalle pareti di cartone.</p>

<p>I parametri del file di configurazione che andrò a trattare riguardano le <strong>modalità di autenticazione</strong> di ssh. La versione che sto usando su debian bullseye è la 8.4p1.
Queste sono:</p>
<ul><li><em>password</em></li>
<li><em>publickey</em></li>
<li><em>keyboard-interactive</em></li>
<li><em>gssapi-with-mic</em></li>
<li><em>hostbased</em></li>
<li><em>none</em></li></ul>

<p>Le prime 3 sono quelle che ci interessano sul serio.</p>

<p>Con ssh posso avere:</p>
<ol><li>una 2FA (ad es. publickey + password)</li>
<li>una MFA (ad es. publickey (qualcosa che sei) + password (qualcosa che sai) + OTP (qualcosa che hai) , se ipotizziamo publickey, in quanto certificato digitale, assimilabile al rilievo biometrico).</li></ol>

<p>Per realizzare i due scenari c&#39;è bisogno di settare con attenzione ssh per non rischiare di lasciare voragini invece che mettere in sicurezza il servizio.</p>

<p>Suppongo che ssh sia già settato come si deve, ciò che andrò a toccare sarà:</p>
<ul><li><em><strong>UsePAM</strong></em>
Abilita o meno l&#39;uso di PAM</li>
<li><em><strong>ChallengeResponseAuthentication (KbdInteractiveAuthentication dalla 8.8)</strong></em>
Permette di applicare lo schema Challenge-Response per l&#39;autenticazione</li>
<li><em><strong>PublicKeyAuthentication</strong></em>
Abilita o meno l&#39;autenticazione con chiave pubblica</li>
<li><em><strong>PasswordAutentication</strong></em>
Abilita o meno l&#39;autenticazione con password</li>
<li><em><strong>AuthenticationMethods</strong></em>
È la lista  (l&#39;elenco precedente) dei metodi di autenticazione che vogliamo permettere.
Se gli elementi sono separati da una virgola, vuol dire che sono <strong>tutti obbligatori</strong> (per avere un&#39;autenticazione multipla per es.).
Se sono separati da uno spazio, vuol dire che sono <strong>facoltativi</strong>.
Es. <code>publickey,password password publickey,password,keyboard-interactive</code>.
Vuol dire che mi posso autenticare fornendo chiave <strong>e</strong> password <strong>oppure</strong> password <strong>oppure</strong> chiave+password+otp
È abbastanza chiaro che una configurazione del genere può essere molto pericolosa perché il suo livello di robustezza dipende dal suo anello più debole (la password in questo caso) che può vanificare tutti gli altri.</li></ul>

<p>Ogni modifica del file di configurazione richiederà il <a id="restart">restart</a> del servizio ssh.</p>

<pre><code class="language-bash">systemctl restart sshd.service
</code></pre>

<h3 id="pam">PAM</h3>

<p>Com&#39;è noto, e banalizzando molto, PAM è un sottosistema gnu/linux che fornisce un livello di astrazione a quelle applicazioni, come ssh, che richiedono autenticazione. In questo modo le applicazioni non hanno bisogno di implementarle esplicitamente e, volendo, possono estendere i propri schemi di autenticazione aumentandone la complessità in maniera relativamente semplice.</p>

<p>PAM, insieme ad una autenticazione di tipo challenge-response, ci permetterà di ottenere un&#39;autenticazione multipla.</p>

<h2 id="scenario-1-configurazione-sicura-chiave-pubblica">Scenario 1: Configurazione sicura (chiave pubblica)</h2>

<p>In molti contesti si preferisce abilitare la sola autenticazione con chiave pubblica, proprio per evitare possibili falle. Niente PAM in questo caso ma solo configurazione ssh:</p>

<pre><code>...
UsePAM=no
ChallengeResponseAuthentication=no
PublicKeyAuthentication=yes
PasswordAuthentication=no
AuthenticationMethods=publickey
...
</code></pre>

<p>PAM viene disabilitato perché scegliamo di non affidarci a librerie di autenticazione esterne. Inoltre, in casi estremi, si può pensare che un aggiornamento di PAM possa rompere la compatibilità con qualche libreria invalidando o indebolendo il processo di autenticazione.</p>

<p>Di conseguenza, niente autenticazione di tipo challenge-response, niente autenticazione con password.</p>

<p>Attiviamo solo la <em>PublicKeyAuthentication</em> rafforzando la scelta in <em>AuthenticationMethods</em> dove impostiamo come unico metodo valido <em>publickey</em>. Infine, <a href="#restart" rel="nofollow">riavviamo</a> il servizio.</p>

<p>L&#39;unico modo per accedere al server ssh è possedere una chiave (o un certificato) valida.</p>

<h2 id="scenario-2-2fa-chiave-pubblica-password">Scenario 2: 2FA (chiave pubblica + password)</h2>

<p>Facciamo un passo in più è facciamo in modo che l&#39;accesso al server sia consentito solo a chi possiede sia chiave che password.</p>

<pre><code>...
UsePAM=no
ChallengeResponseAuthentication=no
PublicKeyAuthentication=yes
PasswordAuthentication=yes
AuthenticationMethods=publickey,password
...
</code></pre>

<p>Oltre che specificare il <strong>tipo</strong> di autenticazione (<em>PublickeyAutentication</em> e <em>PasswordAuthentication</em>), imponiamo che il metodo sia quello di esibire <strong>entrambe</strong> le credenziali.</p>

<p>Non impostando <em>AutenticationMethods</em>, varrebbe il default che prevede <strong>uno</strong> fra password, publickey o keyboard-interactive.</p>

<p>L&#39;ultimo sarebbe comunque inutile in questo caso, visto che pam e challenge-response sono disabilitati. Ma non avremmo ottenuto ciò che ci eravamo prefissati.</p>

<p>Una <a id="scenario-2-pam">configurazione analoga</a> è la seguente:</p>

<pre><code>...
UsePAM=yes
ChallengeResponseAuthentication=yes
PublicKeyAuthentication=yes
PasswordAuthentication=no
AuthenticationMethods=publickey,keyboard-interactive
...
</code></pre>

<p><a href="#restart" rel="nofollow">Riavviamo</a> ssh e la nuova autenticazione sarà disponibile come al solito.</p>

<p>È un esempio di come posso usare PAM per rimpiazzare la <em>PasswordAuthentication</em> nativa.
Con una combinazione di PAM e autenticazione challenge-response, attraverso il metodo esplicito <em>keyboard-interactive</em>, l&#39;applicazione autenticherà con un&#39;unica sfida che è la richiesta di password.</p>

<p>Con PAM posso aggiungere altro, ad es. l&#39;otp, come vedremo nel 3° scenario.</p>

<h2 id="scenario-3-mfa-chiave-pubblica-password-otp">Scenario 3: MFA (chiave pubblica + password + otp)</h2>

<p>Lasciamo inalterata la configurazione ssh <a href="#scenario-2-pam" rel="nofollow">dello scenario 2</a>, quella che fa uso di pam.
Bisogna innanzittutto installare il plugin per l&#39;otp.</p>

<p>Sistemi debian-based:</p>

<pre><code class="language-bash">apt install libpam-google-authenticator
</code></pre>

<p>Sistemi rpm-based:</p>

<pre><code class="language-bash">dnf install google-authenticator
</code></pre>

<p>Per completezza, giusto perché lo uso, MacOS (via brew):</p>

<pre><code class="language-bash">brew install google-authenticator-libpam
</code></pre>

<p>Dopo l&#39;installazione, il generatore otp va inizializzato lanciando l&#39;eseguibile che porrà una serie di domande:</p>
<ul><li>generare i token su base temporale: Y/N (consigliato <strong>Y</strong>)</li>
<li>creare un file di configurazione nella home dell&#39;utente: Y/N (consigliato <strong>Y</strong>)</li>
<li>disabilitare la possibilità che un token possa essere usato più volte: Y/N (consigliato <strong>Y</strong>)</li>
<li>(semplificando) aumentare la finestra temporale di generazione dei token (default 30s): Y/N (consigliato <strong>N</strong>, a meno che la connessione fra client e server non sia <strong>ESTREMAMENTE</strong> lenta)</li>
<li>abilitare il rate-limit per scoraggiare attacchi di brute-force: Y/N (consigliato <strong>Y</strong>)</li></ul>

<p>A seguire, verrà mostrato sia il qr-code (per il caricamento automatico della chiave su un authenticator come <strong><a href="https://f-droid.org/it/packages/org.liberty.android.freeotpplus/" rel="nofollow">FreeOtp+</a></strong>) che la chiave privata (se si vuole procedere con la configurazione manuale dell&#39;authenticator o dello <a href="https://noblogo.org/aytin/generazione-otp-via-bash" rel="nofollow">script visto tempo fa</a>), necessari per la fornitura del primo codice che inizializza il processo.</p>

<p>Infine configuriamo PAM per sshd.
In /etc/pam.d/sshd dobbiamo imporre che il processo di autorizzazione <strong>includa obbligatoriamente</strong> l&#39;otp. Lo faremo aggiungendo una riga contenente il riferimento alla libreria che lo  implementa:</p>

<pre><code>auth required pam_google_authenticator.so
</code></pre>

<p>Il solito <a href="#restart" rel="nofollow">riavvio</a> di ssh (alcuni consigliano anche di fare il reboot della macchina per inizializzare correttamente il generatore di otp ma non ho trovato una giustificazione convincente del perché) completa il lavoro.</p>

<p>Per autenticarsi sul server ssh ora serviranno:</p>
<ul><li>chiave pubblica</li>
<li>password</li>
<li>otp</li></ul>

<h1 id="scenario-3bis-2fa-chiave-pubblica-otp">Scenario 3bis: 2FA (chiave pubblica + otp)</h1>

<p>Se invece volessi avere una 2FA come <a href="#scenario-2-pam" rel="nofollow">nello scenario 2</a>, ma con otp invece che con password, posso procedere così.
Si lascia inalterata la configurazione ssh e si commenta una riga dalla configurazione di PAM:</p>

<p>Su /etc/pam.d/sshd commentare la seguente riga così:</p>

<pre><code>...
#@include common-auth
...
</code></pre>

<p>In questo modo, si elimina la richiesta della password utente dalle “sfide” della challenge-response e rimane la sola richiesta otp.</p>

<h2 id="tips">Tips</h2>

<p>Attenzione quando si gioca con i metodi di autenticazione ssh.
Ci sono buone possibilità che vi autoescludiate dal vostro server.
Basta avere <em>keyboard-interactive</em> (che implica un&#39;autenticazione di tipo challenge-response) fra i metodi di autenticazione obbligatori e pam disattivato.
Ecco un esempio:</p>

<pre><code>...
usePAM no 
ChallengeResponseAuthentication yes
PasswordAuthentication no
PubkeyAuthentication no
AuthenticationMethods keyboard-interactive
...
</code></pre>

<p>Oppure, ancora più subdolo, lo scenario 3 con pam disabilitato, ossia:
<strong>configurazione ssh</strong></p>

<pre><code>...
usePAM no 
ChallengeResponseAuthentication yes
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
...
</code></pre>

<p>In questi casi, l&#39;autenticazione fallirà con questo errore: <em>“Permission denied (keyboard-interactive)”</em> perché non sarà disponibile <strong>nessuna</strong> interazione da tastiera (es. una password) e noi rimarremmo chiusi irrimediabilmente fuori dal nostro server.</p>

<p><a href="/aytin/tag:ssh" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ssh</span></a> <a href="/aytin/tag:otp" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">otp</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/abilitare-la-2fa-in-ssh</guid>
      <pubDate>Thu, 18 May 2023 15:57:05 +0000</pubDate>
    </item>
    <item>
      <title>Generazione OTP via bash</title>
      <link>https://noblogo.org/aytin/generazione-otp-via-bash</link>
      <description>&lt;![CDATA[(pubblicato il 30 gennaio 2021)&#xA;otp&#xA;smalliFonte: a href=&#34;https://www.flaticon.com/free-icons/otp&#34; title=&#34;otp icons&#34;Otp icons created by Chanut-is-Industries - Flaticon/a/i/small&#xA;&#xA;Per buona parte del mio tempo sul pc apro una shell, per cui trovo comodo spostare il meno possibile le mani dalla tastiera. Usando spesso 2FA, ho pensato ad un modo per avere un OTP usando bash.&#xA;!--more--&#xA;Il tool che fa al caso mio è oathtool che, per i miei scopi, è sufficiente invocare in questo modo:&#xA;oathtool --totp -b key&#xA;dove \key\ è una stringa base32 bella lunga.&#xA;&#xA;Chiaramente non voglio doverla scrivere ogni volta, nè voglio lasciarla in chiaro. Occorre che:&#xA;&#xA;la chiave sia cifrata e decifrata solamente quando occorre;&#xA;l&#39;output non arrivi su stdout per non doverlo copiare a mia volta (e lasciarlo comunque visibile)&#xA;&#xA;Al punto 1. si risponde con gpg o openssl.&#xA;&#xA;Al punto 2. si risponde con xsel (Gnu/Linux) o pbcopy (MacOS) che trasferiscono l&#39;output di un comando nella clipboard.&#xA;oathtool --totp -b &lt;&lt; $(gpg -q --decrypt --pinentry-mode loopback &lt;filechiavecifrato) | xsel -bi&#xA;E veniamo quindi alla:&#xA;Versione 1&#xA;!/bin/bash&#xA;&#xA;# Path del file cifrato contentente la chiave # supponiamo sia di google&#xA;KEY2FAFILE=&#34;$1&#34;&#xA;&#xA;oathtool --totp -b &lt;&lt;&lt; $(gpg -q --decrypt --pinentry-mode loopback &#34;${KEY2FAFILE}&#34;) | xsel -bi&#xA;Non è nemmeno uno script. Potrebbe essere direttamente un alias.&#xA;&#xA;ustrongVANTAGGI/strong/u&#xA;&#xA;Estremamente compatto&#xA;Si sfrutta nativamente l&#39;autocomplete col TAB per i file da dare all&#39;input&#xA;L&#39;univocità dei nomi è garantita dal file system&#xA;&#xA;ustrongSVANTAGGI/strong/u&#xA;&#xA;Crea un file per ogni codice e, alla lunga potrebbe generare confusione&#xA;Necessità di creare una password di cifratura per ogni file (potenzialmente tutte diverse)&#xA;&#xA;Versione 2&#xA;Mi occorre quindi un file nome-valore con separatore. Ad es. il simbolo  &#34;:&#34;&#xA;account1:JD88EIDIKJDKMDI3IEJDMDKJKDJKDKPA&#xA;account2:JDNBLASPUQRIEKM89478JMFKOVJDOQKJ&#xA;account3:OIJWGDVLOIQ94KDKSUD9KSLWOER9W3ODF&#xA;account4:MVNMWIQPQYSKGPRIGNFG24KFG9E49RPWQ&#xA;    &#xA;    ...&#xA;    &#xA;accountn:IWPQSLNCGK49TOWODIR483IRIWOFOPIQO&#xA;Nello script, la variabile KEYS\2FA\FILE memorizza il full path del file cifrato dei codici, mentre l&#39;account deve essere fornito in input. In caso contrario, viene restituita la lista degli account disponibili.&#xA;&#xA; Se l&#39;account è valido, il file viene decifrato e viene estratto il corrispondente codice che viene memorizzato direttamente nella clipboard.&#xA;!/usr/bin/bash&#xA;&#xA;Path del file cifrato contentente i codici 2FA&#xA;KEYS2FAFILE=&#34;path/keys2fa.gpg&#34;&#xA;&#xA;Acquisisce il nome account&#xA;ACCOUNT=$1&#xA;&#xA;Decifra e carica in ram il contenuto del file cifrato&#xA;KEYS2FAFILEDEC=$(gpg --decrypt  --pinentry-mode loopback  &#34;${KEYS2FAFILE}&#34; 2  /dev/null)&#xA;&#xA;Se non c&#39;è nessun argomento, restituisce la lista degli account&#xA;if [[ -z &#34;${ACCOUNT}&#34; ]]; then&#xA;    while read LINE; do&#xA;        cut -d&#34;:&#34; -f 1 &lt;&lt;&lt; ${LINE}&#xA;    done &lt;&lt;&lt; $(echo &#34;${KEYS2FAFILEDEC}&#34;)&#xA;    exit&#xA;else&#xA;    # Estrae l&#39;elemento contenente l&#39;id dato in input&#xA;    KEY=$(echo &#34;${KEYS2FAFILEDEC}&#34; | grep ${ACCOUNT} | cut -d&#34;:&#34; -f 2)&#xA;&#xA;    # Se la chiave esiste, restituisce l&#39;otp direttamente nella clipboard&#xA;    # altrimenti esce con errore&#xA;    if [[ -z &#34;${KEY}&#34; ]]; then&#xA;        echo &#34;Account non esistente&#34;&#xA;        exit 1&#xA;    else&#xA;        # Calcola l&#39;otp e lo trasferisce nella clipboard con pbcopy&#xA;        oathtool --totp -b &#34;${KEY}&#34; | xsel -bi&#xA;        echo &#34;Fatto.&#34;&#xA;    fi&#xA;fi&#xA;ustrongVANTAGGI/strong/u&#xA;&#xA;Unico entry-point per la gestione degli account (un&#39;unica password per la cifratura del file&#xA;Più semplice da allocare&#xA;&#xA;ustrongSVANTAGGI/strong/u&#xA;&#xA;L&#39;univocità degli account deve essere garantita dall&#39;utente.&#xA;Perdita della funzionalità di autocomplete in fase di inserimento dati&#xA;&#xA;Provo ad esplorare anche una struttura differente, più espressiva se vogliamo. Invece di un file nome-valore, uso un json così strutturato:&#xA;&#xA;Versione 3&#xA;{&#xA;  &#34;accounts&#34;: [&#xA;    {&#xA;      &#34;id&#34;: &#34;account1&#34;,&#xA;      &#34;secret&#34;: &#34;JD88EIDIKJDKMDI3IEJDMDKJKDJKDKPA&#34;&#xA;    },&#xA;    {&#xA;      &#34;id&#34;: &#34;account2&#34;,&#xA;      &#34;secret&#34;: &#34;JDNBLASPUQRIEKM89478JMFKOVJDOQKJ&#34;&#xA;    },&#xA;    {&#xA;      &#34;id&#34;: &#34;account3&#34;,&#xA;      &#34;secret&#34;: &#34;OIJWGDVLOIQ94KDKSUD9KSLWOER9W3ODF&#34;&#xA;    },&#xA;    {&#xA;      &#34;id&#34;: &#34;account4&#34;,&#xA;      &#34;secret&#34;: &#34;MVNMWIQPQYSKGPRIGNFG24KFG9E49RPWQ&#34;&#xA;    },&#xA;    &#xA;    ...&#xA;    &#xA;    {&#xA;      &#34;id&#34;: &#34;accountn&#34;,&#xA;      &#34;secret&#34;: &#34;IWPQSLNCGK49TOWODIR483IRIWOFOPIQO&#34;&#xA;    }&#xA;  ]&#xA;}&#xA;Un array, accounts, di oggetti nome-valore.&#xA;&#xA;Lo script che fa il parsing e l&#39;estrazione non è molto diverso dal precedente.&#xA;!/usr/local/bin/bash&#xA;&#xA;Path del file cifrato contentente i codici 2FA&#xA;JSON2FAFILE=path/json2fa.gpg&#xA;&#xA;Acquisisce il nome account&#xA;ACCOUNT=$1&#xA;&#xA;Carica in ram il contenuto del file json cifrato&#xA;JSON2FAFILEDEC=$(gpg --decrypt  --pinentry-mode loopback  &#34;${JSON2FAFILE}&#34; 2  /dev/null)&#xA;&#xA;Se non c&#39;è nessun argomento, restituisce la lista degli account&#xA;- jq -c &#39;.accounts[]&#39; restituisce una lista contenenente tante linee per quanti sono gli elementi.&#xA;- La lista viene data in pasto al ciclo while attraverso l&#39;operatore &lt;&lt;&lt; (here-string)&#xA;- Da ogni linea viene estratto il valore del campo &#34;id&#34; sempre attraverso l&#39;operatore &lt;&lt;&lt;&#xA;&#xA;if [[ -z &#34;${ACCOUNT}&#34; ]]; then&#xA;    while read LINE; do&#xA;        jq -r &#39;.id&#39; &lt;&lt;&lt; ${LINE}&#xA;    done &lt;&lt;&lt; $(echo &#34;${JSON2FAFILEDEC}&#34; | jq -c &#39;.accounts[]&#39;)&#xA;    exit&#xA;else&#xA;    # Estrae dall&#39;array l&#39;elemento contenente l&#39;id dato in input&#xA;    KEY=$(jq -r --arg ID ${ACCOUNT} &#39;.accounts[] | select(.id | contains($ID)).secret&#39; &lt;&lt;&lt; ${JSON2FAFILE_DEC})&#xA;&#xA;    # Se la chiave esiste, restituisce l&#39;otp direttamente nella clipboard&#xA;    # altrimenti esce con errore&#xA;    if [[ -z &#34;${KEY}&#34; ]]; then&#xA;        echo &#34;Account non esistente&#34;&#xA;        exit 1&#xA;    else&#xA;        # Calcola l&#39;otp e lo trasferisce nella clipboard con xsel&#xA;        oathtool --totp -b &#34;${KEY}&#34; | xsel -bi&#xA;        echo &#34;Fatto.&#34;&#xA;    fi&#xA;fi&#xA;#bash #otp #scripting #shell ]]&gt;</description>
      <content:encoded><![CDATA[<p><strong><em>(pubblicato il 30 gennaio 2021)</em></strong>
<img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/0fca8ea69-e1c06b/Jm77gCXX9v4y/7IVttwKSmhThLBGuFctXh2BMZau1cgRi2Grgjhmh.jpg" alt="otp">
<small><i>Fonte: <a href="https://www.flaticon.com/free-icons/otp" title="otp icons" rel="nofollow">Otp icons created by Chanut-is-Industries – Flaticon</a></i></small></p>

<p>Per buona parte del mio tempo sul pc <a href="https://noblogo.org/aytin/merge-delle-history-in-tempo-reale" rel="nofollow">apro una shell</a>, per cui trovo comodo spostare il meno possibile le mani dalla tastiera. Usando spesso 2FA, ho pensato ad un modo per avere un OTP usando bash.

Il tool che fa al caso mio è <a href="http://www.nongnu.org/oath-toolkit/oathtool.1.html" rel="nofollow">oathtool</a> che, per i miei scopi, è sufficiente invocare in questo modo:</p>

<pre><code class="language-bash">oathtool --totp -b &lt;key&gt;
</code></pre>

<p>dove <em>&lt;key&gt;</em> è una stringa base32 bella lunga.</p>

<p>Chiaramente non voglio doverla scrivere ogni volta, nè voglio lasciarla in chiaro. Occorre che:</p>
<ol><li>la chiave sia cifrata e decifrata solamente quando occorre;</li>
<li>l&#39;output non arrivi su stdout per non doverlo copiare a mia volta (e lasciarlo comunque visibile)</li></ol>

<p>Al punto 1. si risponde con <a href="https://www.gnupg.org" rel="nofollow">gpg</a> o <a href="https://www.openssl.org" rel="nofollow">openssl</a>.</p>

<p>Al punto 2. si risponde con <strong>xsel</strong> (Gnu/Linux) o <strong>pbcopy</strong> (MacOS) che trasferiscono l&#39;output di un comando nella clipboard.</p>

<pre><code class="language-bash">oathtool --totp -b &lt;&lt;&lt; $(gpg -q --decrypt --pinentry-mode loopback &lt;file_chiave_cifrato&gt;) | xsel -bi
</code></pre>

<p>E veniamo quindi alla:</p>

<h2 id="versione-1">Versione 1</h2>

<pre><code class="language-bash">#!/bin/bash

# Path del file cifrato contentente la chiave # supponiamo sia di google
KEY_2FA_FILE=&#34;$1&#34;

oathtool --totp -b &lt;&lt;&lt; $(gpg -q --decrypt --pinentry-mode loopback &#34;${KEY_2FA_FILE}&#34;) | xsel -bi
</code></pre>

<p>Non è nemmeno uno script. Potrebbe essere direttamente un alias.</p>

<p><u><strong>VANTAGGI</strong></u></p>
<ul><li>Estremamente compatto</li>
<li>Si sfrutta nativamente l&#39;autocomplete col TAB per i file da dare all&#39;input</li>
<li>L&#39;univocità dei nomi è garantita dal file system</li></ul>

<p><u><strong>SVANTAGGI</strong></u></p>
<ul><li>Crea un file per ogni codice e, alla lunga potrebbe generare confusione</li>
<li>Necessità di creare una password di cifratura per ogni file (potenzialmente tutte diverse)</li></ul>

<h2 id="versione-2">Versione 2</h2>

<p>Mi occorre quindi un file nome-valore con separatore. Ad es. il simbolo  “:”</p>

<pre><code>account_1:JD88EIDIKJDKMDI3IEJDMDKJKDJKDKPA
account_2:JDNBLASPUQRIEKM89478JMFKOVJDOQKJ
account_3:OIJWGDVLOIQ94KDKSUD9KSLWOER9W3ODF
account_4:MVNMWIQPQYSKGPRIGNFG24KFG9E49RPWQ
    
    ...
    
account_n:IWPQSLNCGK49TOWODIR483IRIWOFOPIQO
</code></pre>

<p>Nello script, la variabile <strong>KEYS_2FA_FILE</strong> memorizza il full path del file cifrato dei codici, mentre l&#39;account deve essere fornito in input. In caso contrario, viene restituita la lista degli account disponibili.</p>

<p> Se l&#39;account è valido, il file viene decifrato e viene estratto il corrispondente codice che viene memorizzato direttamente nella clipboard.</p>

<pre><code class="language-bash">#!/usr/bin/bash

# Path del file cifrato contentente i codici 2FA
KEYS_2FA_FILE=&#34;&lt;path&gt;/keys_2fa.gpg&#34;

# Acquisisce il nome account
ACCOUNT=$1

# Decifra e carica in ram il contenuto del file cifrato
KEYS_2FA_FILE_DEC=$(gpg --decrypt  --pinentry-mode loopback  &#34;${KEYS_2FA_FILE}&#34; 2&gt;/dev/null)

# Se non c&#39;è nessun argomento, restituisce la lista degli account
if [[ -z &#34;${ACCOUNT}&#34; ]]; then
    while read LINE; do
        cut -d&#34;:&#34; -f 1 &lt;&lt;&lt; ${LINE}
    done &lt;&lt;&lt; $(echo &#34;${KEYS_2FA_FILE_DEC}&#34;)
    exit
else
    # Estrae l&#39;elemento contenente l&#39;id dato in input
    KEY=$(echo &#34;${KEYS_2FA_FILE_DEC}&#34; | grep ${ACCOUNT} | cut -d&#34;:&#34; -f 2)

    # Se la chiave esiste, restituisce l&#39;otp direttamente nella clipboard
    # altrimenti esce con errore
    if [[ -z &#34;${KEY}&#34; ]]; then
        echo &#34;Account non esistente&#34;
        exit 1
    else
        # Calcola l&#39;otp e lo trasferisce nella clipboard con pbcopy
        oathtool --totp -b &#34;${KEY}&#34; | xsel -bi
        echo &#34;Fatto.&#34;
    fi
fi
</code></pre>

<p><u><strong>VANTAGGI</strong></u></p>
<ul><li>Unico entry-point per la gestione degli account (un&#39;unica password per la cifratura del file</li>
<li>Più semplice da allocare</li></ul>

<p><u><strong>SVANTAGGI</strong></u></p>
<ul><li>L&#39;univocità degli account deve essere garantita dall&#39;utente.</li>
<li>Perdita della funzionalità di autocomplete in fase di inserimento dati</li></ul>

<p>Provo ad esplorare anche una struttura differente, più espressiva se vogliamo. Invece di un file nome-valore, uso un json così strutturato:</p>

<h2 id="versione-3">Versione 3</h2>

<pre><code>{
  &#34;accounts&#34;: [
    {
      &#34;id&#34;: &#34;account_1&#34;,
      &#34;secret&#34;: &#34;JD88EIDIKJDKMDI3IEJDMDKJKDJKDKPA&#34;
    },
    {
      &#34;id&#34;: &#34;account_2&#34;,
      &#34;secret&#34;: &#34;JDNBLASPUQRIEKM89478JMFKOVJDOQKJ&#34;
    },
    {
      &#34;id&#34;: &#34;account_3&#34;,
      &#34;secret&#34;: &#34;OIJWGDVLOIQ94KDKSUD9KSLWOER9W3ODF&#34;
    },
    {
      &#34;id&#34;: &#34;account_4&#34;,
      &#34;secret&#34;: &#34;MVNMWIQPQYSKGPRIGNFG24KFG9E49RPWQ&#34;
    },
    
    ...
    
    {
      &#34;id&#34;: &#34;account_n&#34;,
      &#34;secret&#34;: &#34;IWPQSLNCGK49TOWODIR483IRIWOFOPIQO&#34;
    }
  ]
}
</code></pre>

<p>Un array, <em>accounts</em>, di oggetti nome-valore.</p>

<p>Lo script che fa il parsing e l&#39;estrazione non è molto diverso dal precedente.</p>

<pre><code class="language-bash">#!/usr/local/bin/bash

# Path del file cifrato contentente i codici 2FA
JSON_2FA_FILE=&lt;path&gt;/json_2fa.gpg

# Acquisisce il nome account
ACCOUNT=$1

# Carica in ram il contenuto del file json cifrato
JSON_2FA_FILE_DEC=$(gpg --decrypt  --pinentry-mode loopback  &#34;${JSON_2FA_FILE}&#34; 2&gt;/dev/null)

# Se non c&#39;è nessun argomento, restituisce la lista degli account
# - jq -c &#39;.accounts[]&#39; restituisce una lista contenenente tante linee per quanti sono gli elementi.
# - La lista viene data in pasto al ciclo while attraverso l&#39;operatore &lt;&lt;&lt; (here-string)
# - Da ogni linea viene estratto il valore del campo &#34;id&#34; sempre attraverso l&#39;operatore &lt;&lt;&lt;

if [[ -z &#34;${ACCOUNT}&#34; ]]; then
    while read LINE; do
        jq -r &#39;.id&#39; &lt;&lt;&lt; ${LINE}
    done &lt;&lt;&lt; $(echo &#34;${JSON_2FA_FILE_DEC}&#34; | jq -c &#39;.accounts[]&#39;)
    exit
else
    # Estrae dall&#39;array l&#39;elemento contenente l&#39;id dato in input
    KEY=$(jq -r --arg ID ${ACCOUNT} &#39;.accounts[] | select(.id | contains($ID)).secret&#39; &lt;&lt;&lt; ${JSON_2FA_FILE_DEC})

    # Se la chiave esiste, restituisce l&#39;otp direttamente nella clipboard
    # altrimenti esce con errore
    if [[ -z &#34;${KEY}&#34; ]]; then
        echo &#34;Account non esistente&#34;
        exit 1
    else
        # Calcola l&#39;otp e lo trasferisce nella clipboard con xsel
        oathtool --totp -b &#34;${KEY}&#34; | xsel -bi
        echo &#34;Fatto.&#34;
    fi
fi
</code></pre>

<p><a href="/aytin/tag:bash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bash</span></a> <a href="/aytin/tag:otp" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">otp</span></a> <a href="/aytin/tag:scripting" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">scripting</span></a> <a href="/aytin/tag:shell" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">shell</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/generazione-otp-via-bash</guid>
      <pubDate>Tue, 28 Feb 2023 07:59:24 +0000</pubDate>
    </item>
  </channel>
</rss>