La generazione della chiave non richiede un file temporaneo, e farne a meno corregge meno di quanto lascino intendere la maggior parte delle guide. Ciò che rimuove è un ciclo di vita del file e la corsa alla pulizia che lo circonda. Ciò che lascia intatto è ogni occasione di divulgare il segreto in seguito. Il problema di correttezza in questi script di solito sta altrove, perché la diagnostica e il materiale della chiave viaggiano su flussi diversi.

Il file non è mai stato l'esposizione che pensavi

Un file temporaneo è un rischio concreto quando è leggibile da tutti, quando sopravvive a un crash o quando si salta un passaggio di pulizia dopo un'eccezione. Sono rischi reali e vale la pena correggerli. Sono anche locali, visibili e facili da testare. Nomina ciascuno nel tuo script prima di concludere che la modifica fosse cosmetica.

I rischi più silenziosi stanno a valle: la chiave stampata durante il debug, l'eccezione che serializza l'intero oggetto risultato, il gestore di crash che scrive un dump del core, l'aggregatore di log che riceve il percorso del file e poi il contenuto. Evitare un file temporaneo non fa nulla per nessuno di questi, e credere il contrario è il modo in cui una riscrittura benintenzionata lascia il segreto più esposto di prima. Tratta la modifica come un miglioramento in una sequenza, non come la soluzione.

Cosa scrive il client quando non viene dato un nome di file

Le versioni attuali del client inviano la chiave generata all'output standard quando il comando della chiave viene dato senza un percorso di output. È questo comportamento documentato a rendere praticabile l'approccio in memoria, e rimuove la necessità del vecchio trucco di puntare lo strumento a un percorso di dispositivo.

import subprocess
proc = subprocess.run(
    ["openvpn", "--genkey", "tls-crypt"],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    check=True,
)
key_material = proc.stdout

Passa il comando come una lista. Qui non serve alcuna espansione della shell, e abilitarne una renderebbe il confine degli argomenti dipendente da virgolette che non controlli. Usa l'eseguibile previsto tramite percorso assoluto se lo script può girare con un percorso di ricerca diverso da quello che ti aspetti.

Il controllo del codice di ritorno impedisce al percorso di successo di proseguire dopo una chiamata fallita. Senza di esso, una stringa di byte vuota può fluire in avanti e fallire solo molto più tardi, nel punto in cui la chiave viene usata e il messaggio di errore non menziona più affatto la generazione.

Due flussi, due significati

L'output standard porta la chiave. L'errore standard porta tutto ciò che lo strumento vuole dirti, compresi gli avvisi su configurazione, versione e tipo di chiave. Redirigere entrambi in un solo buffer è l'errore che produce una chiave dall'aspetto plausibile con una frase cucita nel mezzo.

Tieni separato anche il percorso di errore. Quando la chiamata fallisce, segnala il comando che ha fallito e lo stato di uscita, poi decidi deliberatamente se qualche parte dell'errore standard sia sicura da mostrare. Scaricare l'intero oggetto risultato in un log è la scorciatoia abituale, e può portare con sé la chiave.

Una lettura sicura per i binari conta se in seguito calcoli l'hash del materiale o lo confronti. La modalità testo con una codifica inattesa può alterare byte che non erano mai destinati a essere testo, e una chiave alterata è indistinguibile da una sbagliata finché non fallisce una stretta di mano.

Se comunque lo conservi, fallo deliberatamente

La maggior parte delle distribuzioni alla fine ha bisogno della chiave su disco, sul gateway o in un archivio di segreti. Scrivila una volta, con permessi restrittivi fin dalla creazione invece di un chmod successivo, e rendi la scrittura atomica così che un file parziale non diventi mai quello che un servizio legge all'avvio. Una rinomina da un percorso nella stessa directory di solito basta per questo. Rimuovi il percorso di preparazione sul ramo di errore, perché la scrittura fallita è esattamente la copia che le persone dimenticano.

Imposta il modo del file quando viene creato, e mantieni restrittivo anche il modo della directory. Evita qualsiasi percorso sotto una posizione che un processo di backup spazza senza pensarci, perché un segreto in un backup notturno è un segreto in ogni copia di quel backup. Lo stesso ragionamento vale per un volume condiviso che altri servizi possono leggere.

Una chiave condivisa non è un'identità

Generare questo materiale non emette un certificato, non iscrive un client e non stabilisce chi si connette. La chiave condivisa protegge un canale tra parti che già si fidano l'una dell'altra; l'identità viene ancora dal certificato e da qualsiasi autenticazione che gli stia davanti.

Anche i tipi di chiave non sono intercambiabili. Una chiave simmetrica per una funzione non è un sostituto diretto per un'altra, e le versioni più recenti aggiungono le proprie varianti con file diversi a ciascuna estremità. Genera il tipo che la tua configurazione nomina davvero, poi usalo nel ruolo che quel tipo definisce.

Prova il risultato con una connessione reale invece di ispezionare la dimensione del file. Se la stretta di mano si completa e i log non mostrano avvisi sulla chiave, il percorso di generazione è corretto; se la chiave fosse stata troncata da un flusso unito, la connessione fallirebbe in un modo che indica il peer invece dello script.

Articoli correlati