Proxy di credenziali — tecnico
Come funziona il proxy.
Contro cosa protegge. Contro cosa non protegge.
Questa pagina è destinata a revisori della sicurezza, penetration tester e ingegneri che valutano il modello di minaccia del proxy. Descrive cosa fa il proxy a livello di protocollo, dove risiedono le credenziali in memoria e quali superfici di attacco rimangono.
Architettura
Il proxy è un proxy HTTPS MITM basato su CONNECT. Un agente IA imposta HTTPS_PROXY per puntare ad esso. Quando l'agente effettua una richiesta HTTPS, il proxy intercetta la connessione TLS, ispeziona gli header della richiesta per riferimenti alle credenziali, li risolve rispetto alla cassaforte Clavitor e inoltra la richiesta con le credenziali iniettate all'API upstream.
Il proxy ascolta su 127.0.0.1:1983 per impostazione predefinita — il pattern sidecar in cui il proxy e l'agente condividono un host. Per distribuzioni condivise (un proxy che serve più agenti su una rete privata, sidecar di container per più carichi di lavoro, host proxy dedicato), l'interfaccia di ascolto è configurabile tramite CLAVITOR_PROXY_LISTEN.
Il proxy è un binario Go standalone. Nessun CGO. Tutta la crittografia del protocollo Clavitor passa attraverso un'implementazione canonica Rust compilata in WebAssembly e caricata tramite wazero all'avvio.
Gestione TLS
Il proxy genera una CA root ECDSA P-256 autofirmata al primo avvio, persistita nella directory del binario con modalità 0600. Per ogni host upstream, un certificato foglia viene emesso su richiesta, firmato da questa CA e memorizzato nella cache in memoria con rimozione limitata (1.000 host). I certificati foglia sono validi per 24 ore e rigenerati in modo trasparente alla 23ª ora per prevenire la scadenza a metà sessione.
L'agente deve fidarsi del certificato CA del proxy. Esportarlo con clavitor-proxy ca.
Le connessioni upstream utilizzano TLS 1.3 minimo con negoziazione ALPN per HTTP/2 e HTTP/1.1. Il pool di certificati di sistema viene utilizzato per la verifica upstream. Nessun certificate pinning — il proxy si fida di ciò di cui si fida il sistema operativo.
Le credenziali non vengono mai memorizzate nella cache, mai scritte su disco e mai conservate più a lungo di una richiesta HTTP.
| Fase | Dove esiste la credenziale | Durata |
|---|---|---|
| A riposo nella cassaforte | Testo cifrato AES-GCM nel database della cassaforte | Fino all'eliminazione |
| In transito verso il proxy | Risposta JSON crittografata TLS dall'API della cassaforte | Un round-trip HTTP |
| Decifrata nel proxy | Memoria del processo (stringa Go sull'heap) | Una richiesta HTTP |
| Iniettata nella richiesta upstream | Byte crittografati TLS sul filo verso l'upstream | Una richiesta HTTP |
Il proxy detiene la chiave di decrittografia delle credenziali dell'agente (16 byte) in memoria per tutta la sua durata di esecuzione. Viene caricata dalla configurazione sidecar crittografata (formato CLV1) all'avvio e cancellata allo spegnimento grazioso. La chiave non lascia mai il processo.
La configurazione sidecar è crittografata con AES-128-GCM e HMAC-SHA256 utilizzando chiavi deterministiche derivate da un seed statico. Questo è un offuscamento, non riservatezza — il confine di sicurezza sono i permessi del file (0600) e il possesso del file. Il formato CLV1 è condiviso tra il proxy, la CLI e l'estensione del browser.
Modalità di risoluzione
Modalità 1 — placeholder esplicito
L'agente include un riferimento clavitor://Entry/field in un header di richiesta. Il proxy cerca nella cassaforte la voce per nome, la recupera, decifra il campo nominato e sostituisce il placeholder con il valore reale.
Se la ricerca restituisce zero o più di un risultato, il proxy restituisce 502 con un codice di errore stabile. Il placeholder non viene mai rimosso e inoltrato così com'è.
Modalità 2 — corrispondenza URL
Quando non è presente alcun placeholder, il proxy chiede alla cassaforte le voci il cui campo URL corrisponde all'host upstream. Se esiste esattamente una corrispondenza con una forma di campo riconosciuta, il proxy inietta automaticamente le credenziali.
Zero corrispondenze → passthrough (nessuna aspettativa di credenziali). Corrispondenze multiple → 502 con indicazioni di disambiguazione. Forma di campo sconosciuta → 502.
L'albero decisionale è deterministico: placeholder presente → risolvi o fallisci. Nessun placeholder → corrispondenza URL o passthrough. Non esiste un percorso di fallback silenzioso in cui una risoluzione fallita comporta una richiesta all'upstream senza credenziali.
Per impostazione predefinita, la cassaforte vede l'ID agente del proxy su ogni richiesta. Limiti di frequenza, controlli di ambito e voci di audit sono attribuiti al proxy.
Quando più agenti condividono un'istanza proxy, il placeholder può includere un ID agente: clavitor://agentid@Entry/field. Il proxy invia questo ID agente alla cassaforte, che applica gli ambiti e i limiti di frequenza di quell'agente e registra l'accesso ad esso. L'ID agente è il valore esadecimale di 32 caratteri mostrato nella pagina dei dettagli dell'agente nell'interfaccia utente della cassaforte.
# Without agent ID — attributed to the proxy Authorization: Bearer clavitor://OpenAI/key # With agent ID — attributed to agent 0102030405060708090a0b0c0d0e0f10 Authorization: Bearer clavitor://0102030405060708090a0b0c0d0e0f10@OpenAI/key
| Distribuzione | Modello di identità | Isolamento |
|---|---|---|
| Un proxy per agente | ID proxy = ID agente (predefinito) | Completo — binario separato, configurazione, ambito, limiti di frequenza |
| Proxy condiviso, nessun ID agente nell'URL | Tutti gli agenti condividono l'ID del proxy | Ambito e limiti di frequenza condivisi |
Proxy condiviso + agentid@ nell'URL | Identità per agente | Ambito, limiti di frequenza e audit per agente |
L'ID agente nell'URL non è un meccanismo di autenticazione — il token CVT del proxy autentica la connessione. L'ID agente determina l'attribuzione: quali ambiti si applicano, quali limiti di frequenza contano, quale traccia di audit registra l'accesso. La cassaforte rifiuta gli ID agente sconosciuti con un errore evidente.
Sicurezza di rete
Protezione SSRF
Per impostazione predefinita, il proxy blocca le connessioni upstream verso reti private (RFC 1918), metadati delle istanze cloud (169.254.169.254), loopback, link-local e intervalli carrier-grade NAT. Il DNS viene risolto per primo; tutti gli IP restituiti vengono convalidati prima che venga stabilita la connessione TCP, chiudendo la finestra TOCTOU di reindirizzamento DNS.
Sovrascrivere con CLAVITOR_PROXY_ALLOW_PRIVATE=true per gli agenti che accedono legittimamente ad API private.
Pinning del target
L'host di destinazione CONNECT viene catturato all'instaurazione del tunnel e utilizzato per l'intera durata del tunnel. Le richieste successive all'interno del tunnel non possono reindirizzare a un host diverso manipolando l'header Host. Una mancata corrispondenza comporta 502.
Ciò impedisce a un agente di stabilire un tunnel verso api.openai.com e quindi inviare richieste a internal-service.corp.
Gestione degli header
Gli header hop-by-hop vengono rimossi sia dalle richieste che dalle risposte secondo RFC 7230 §6.1: Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection, TE, Trailers, Transfer-Encoding, Upgrade.
Set-Cookie viene rimosso dalle risposte upstream per impedire agli upstream di inserire cookie nel client HTTP dell'agente.
I corpi delle richieste e delle risposte fluiscono senza buffering. I corpi delle richieste sono limitati a 64 MB per impostazione predefinita (CLAVITOR_PROXY_MAX_BODY_MB). I corpi delle risposte fluiscono senza un limite rigido; viene emesso un avviso di log quando Content-Length supera i 100 MB.
In modalità di corrispondenza URL, il proxy mappa le etichette dei campi della cassaforte agli header HTTP:
| Etichetta del campo | Header iniettato |
|---|---|
key, apikey, api_key, token, secret, bearer, access_token | Authorization: Bearer <value> |
x-api-key, api-key | X-API-Key: <value> |
username + password (accoppiati) | Authorization: Basic base64(user:pass) |
| Qualsiasi altra cosa | Rifiutato — ERR-PROXY-052 |
In modalità placeholder, l'agente controlla quale campo viene risolto e dove va. La mappatura sopra si applica solo alla modalità di corrispondenza URL.
Ogni errore produce un codice stabile ERR-PROXY-NNN. Questi codici fanno parte dell'interfaccia pubblica del proxy — gli agenti e gli operatori possono confrontarli per avvisi e debug.
| Intervallo | Categoria |
|---|---|
001–019 | Configurazione (config, init, generazione CA, WASM) |
020–029 | Ciclo di vita del demone |
030–049 | Risoluzione placeholder (URI clavitor://) |
050–069 | Iniezione tramite corrispondenza URL |
070–089 | Upstream / TLS |
I campi di identità sono irraggiungibili
Le voci della cassaforte supportano tre livelli di crittografia. I campi crittografati dalla cassaforte sono metadati in testo chiaro. I campi crittografati dalle credenziali vengono decifrati con la chiave dell'agente. I campi crittografati dall'identità sono crittografati con una chiave che il server e il proxy non hanno mai visto. Solo il proprietario della cassaforte, tramite la propria chiave hardware di sicurezza, può decifrarli.
Se un placeholder fa riferimento a un campo crittografato dall'identità, il proxy restituisce ERR-PROXY-035. Nessun fallback, nessun risultato parziale. Il campo è architettonicamente irraggiungibile dal proxy.
Contro cosa il proxy non protegge
Il modello di minaccia del proxy è un'abilità compromessa o un'iniezione di prompt che induce un agente autenticato a raccogliere credenziali. I limiti di frequenza per agente della cassaforte, le quote di voci uniche e il blocco a due tentativi sono le difese primarie. Il proxy aggiunge un punto di applicazione a livello di rete in cui le credenziali vengono risolte per richiesta e mai detenute dall'agente.
Il proxy viene eseguito sulla stessa macchina dell'agente. Un attaccante con accesso root può leggere la memoria del processo, allegare un debugger o intercettare il traffico di loopback. Il proxy è un livello di iniezione di credenziali, non un confine di sicurezza hardware.
Se l'API upstream ripete la credenziale nella sua risposta (ad esempio, un endpoint "whoami"), l'agente la vede. Il proxy inietta le credenziali nelle richieste, non nelle risposte. Non filtra ciò che ritorna.
Logging
Il proxy registra una riga per ogni CONNECT accettato ed emette righe di errore per i fallimenti. Non registra mai:
- Valori delle credenziali decifrate
- URL completi delle richieste (le stringhe di query possono contenere segreti — vengono registrati solo schema + host + percorso)
- Corpi delle richieste o delle risposte
- La chiave di decrittografia delle credenziali o il contenuto della configurazione sidecar
Quando il proxy rileva che una risposta 400 dall'upstream contiene parole chiave relative all'autenticazione (unauthorized, invalid token, ecc.), registra un suggerimento diagnostico che suggerisce che la credenziale iniettata potrebbe essere obsoleta. La risposta viene inoltrata invariata.
Crittografia
Tutta la crittografia del protocollo Clavitor — decrittografia dei campi AES-GCM, derivazione delle chiavi HKDF, codifica base62, emissione di token CVT, pacchettizzazione/depacchettizzazione della configurazione CLV1 — viene eseguita all'interno di un singolo modulo WebAssembly (clavis_crypto.wasm) caricato tramite wazero, un runtime WASM puro Go. Nessun CGO. Nessuna reimplementazione Go delle primitive Clavitor.
Il modulo WASM è compilato dalla stessa crate Rust (clavis-crypto) utilizzata dal browser, dalla CLI e dalle estensioni del browser. Un'unica fonte di verità, un unico binario, un'unica superficie di audit.
Il proxy utilizza crypto/tls di Go per il wire TLS e crypto/ecdsa per la generazione dei certificati MITM. Queste sono preoccupazioni di trasporto, non operazioni del protocollo Clavitor.
I segreti (chiave di decrittografia delle credenziali, ID agente, ID dispositivo, URL cassaforte) risiedono nella configurazione sidecar CLV1 crittografata, scritta una volta durante clavitor-proxy init. Le manopole operative risiedono nelle variabili d'ambiente:
| Variabile | Predefinito | Scopo |
|---|---|---|
CLAVITOR_PROXY_LISTEN | 127.0.0.1 | Interfaccia di ascolto. Impostata su 0.0.0.0 per distribuzioni condivise, o su un IP di interfaccia specifico. |
CLAVITOR_PROXY_PORT | 1983 | Porta di ascolto |
CLAVITOR_PROXY_ALLOW_PRIVATE | false | Consenti connessioni a reti RFC-1918 / private |
CLAVITOR_PROXY_MAX_BODY_MB | 64 | Limite dimensione corpo richiesta |
CLAVITOR_PROXY_WRITE_TIMEOUT | 300 | Timeout di scrittura risposta in secondi |
CLAVITOR_CONFIG | (directory eseguibile) | Sovrascrive il percorso della configurazione sidecar |
Le manopole operative non sono segreti. Non appartengono alla configurazione crittografata. Appartengono a dove gli strumenti di distribuzione li gestiscono già — l'ambiente.
Rivedere autonomamente.
La crittografia è un singolo artefatto WASM auditabile. Il modello di minaccia è documentato. Se trovate qualcosa che ci è sfuggito, vogliamo saperlo.