Sicurezza
Come è costruito il caveau e cosa si potrebbe trovare al suo interno in caso di violazione.
Ultimo aggiornamento 21 settembre 2026 · AssuredAuth, di CircleRoll LLC
Questa è la descrizione pubblica di come AssuredAuth protegge i segreti dell'autenticazione a due fattori, le password e le carte che vi sono memorizzate. È redatta in modo che un lettore attento alla sicurezza possa verificare ogni affermazione confrontandola con l'app e con i vettori di test pubblicati (disponibili a qualsiasi revisore su richiesta all'indirizzo hello@assuredauth.com). Si limita a riportare la verità, senza fronzoli: nulla viene dichiarato inattaccabile e non vengono fornite promesse in percentuale.
In breve: il caveau si trova in un unico posto, il tuo telefono. Ogni dato in esso contenuto è crittografato con una chiave che l'hardware di sicurezza del telefono custodisce e non può esportare. Non gestiamo alcun server dedicato al caveau, non conserviamo alcuna copia e non possediamo alcuna chiave. Un file di backup lascia il telefono solo dopo essere stato crittografato con una passphrase che non viene mai memorizzata da nessuna parte.
Segnala un problema: hello@assuredauth.com. Vedi la sezione "Segnalazione di una vulnerabilità" alla fine.
1. Cosa è crittografato, con cosa
| Dati | Sul telefono | Chiave |
|---|---|---|
| Segreti per l'autenticazione a due fattori (TOTP/HOTP/seed di Steam) | Sul telefonoPortachiavi (iOS) / Negozio supportato da Android Keystore | ChiaveLa chiave associata all'hardware della piattaforma; la riga del database contiene solo un riferimento (secretRef), mai il seed |
| Password (valore della password, note) | Sul telefonoRiga sigillata: AES-256-GCM, un nonce casuale a 96 bit per valore | ChiaveUna chiave dati casuale a 256 bit, a sua volta incapsulata dalla chiave hardware descritta nel §2 |
| Carte (numero, data di scadenza, nome del titolare, CVC) | Sul telefonoStesso sigillo delle password; il CVC è facoltativo e viene memorizzato solo se lo si inserisce. | ChiaveStessa chiave dati |
| Metadati (nomi dei servizi, nomi utente, icone, ordine di visualizzazione) | Sul telefonoIl database dell'app (SwiftData / Room) | ChiaveProtetto dalla crittografia dei file del sistema operativo; trattato come non segreto |
| File di backup (.authbackup) | Sul telefonoOvunque tu lo metta: File, iCloud Drive, Google Drive appDataFolder, un foglio di condivisione | ChiaveUna chiave derivata dalla tua passphrase (§3). Apple e Google ricevono il file sigillato e nient'altro |
| Companion per Watch / Wear | Sul telefonoPortachiavi dell'orologio / Preferenze condivise crittografate | ChiaveLe chiavi della piattaforma dell'orologio; trasferite tramite il canale del dispositivo associato della piattaforma |
| Traffico proveniente da estensioni desktop (codici monouso su richiesta) | Sul telefonoNon memorizzato; trasmesso come buste crittografate end-to-end. | ChiaveUna coppia di chiavi X25519 per ogni accoppiamento, chiave privata nel portachiavi/archivio chiavi; il relay vede solo il testo cifrato |
La diagnostica non dispone di alcun metodo che accetti un segreto. Nessun evento di analisi contiene un campo del vault. Nessun valore del vault viene mai scritto in un log, in nessuna build.
2. Dove si trovano le chiavi, su ciascuna piattaforma
iOS. La chiave dati è protetta da una chiave generata all'interno dell'Enclave sicura (kSecAttrTokenIDSecureEnclave) con controllo di accesso .privateKeyUsage + .userPresence, accessibilità …ThisDeviceOnly, nel gruppo di accesso Portachiavi condiviso dell'app, in modo che l'estensione di compilazione automatica possa utilizzare la stessa chiave. La chiave privata non può essere letta dall'Enclave dall'app, da un backup o da un debugger; l'Enclave accetta di utilizzarla solo dopo che l'utente è presente (Face ID, Touch ID o codice di accesso del dispositivo). ThisDeviceOnly significa che un backup iCloud o iTunes del telefono non contiene la chiave; un telefono ripristinato si avvia con un vault vuoto e richiede il file di backup e la passphrase. Un telefono senza codice di accesso non può proteggere una chiave .userPresence (l'Enclave si rifiuta di crearne una) e il simulatore segue lo stesso percorso per impostazione predefinita (il suo messaggio di presenza è un avviso a cui nessun test può rispondere): lì la chiave dati è un semplice elemento Portachiavi presente solo sul dispositivo, ancora fuori da ogni backup, ancora illeggibile quando il telefono è bloccato, ma senza un secondo messaggio, e la schermata Sicurezza lo conferma e suggerisce di impostare un codice di accesso.
Android. La chiave dati è incapsulata in una chiave AES-256 di AndroidKeyStore, generata in StrongBox quando il dispositivo ne possiede una (altrimenti TEE), con setUserAuthenticationRequired(true) e una validità di autenticazione di 30 secondi dopo un'autenticazione biometrica o tramite credenziali del dispositivo, setUnlockedDeviceRequired(true) e setInvalidatedByBiometricEnrollment(true) lasciati attivi. Quest'ultimo flag è onesto piuttosto che gravoso: Android lo applica solo alle chiavi che richiedono un'autenticazione biometrica a ogni utilizzo, quindi su questa chiave da 30 secondi con le credenziali del dispositivo consentite non cambia nulla: ciò che impedisce a uno sconosciuto di accedere è che la registrazione richiede il PIN e che la rimozione del blocco schermo invalida la chiave in modo permanente. Le chiavi del keystore non sono esportabili e sono escluse dal backup cloud di Android. Un dominio che un'app nomina nelle proprie viste (webDomain) è considerato attendibile solo da un browser conosciuto; Da qualsiasi altro pacchetto deve trattarsi anche di un pacchetto che il sistema ha verificato per quel pacchetto (Collegamenti alle risorse digitali), poiché qualsiasi app può rivendicare qualsiasi dominio.
Cosa significa questo per un file di database rubato. Il file SQLite e le righe crittografate sono testo cifrato. La chiave per decifrarli risiede nell'hardware di sicurezza del telefono da cui proviene il file e non può essere copiata insieme al file stesso. Non c'è nulla da indovinare offline: la chiave dati è casuale, non deriva da una scelta personale.
3. Il file di backup
I backup sono l'unica cosa che lascia il telefono, quindi sono l'unico punto in cui, in linea di principio, è possibile un attacco offline. La progettazione rende questo tipo di attacco costoso e riduce al minimo le possibilità di successo.
- La passphrase è composta da almeno 12 caratteri (il sistema rifiuta password di lunghezza inferiore e mostra un indicatore di robustezza).
- Nessun suggerimento per la passphrase viene memorizzato da nessuna parte, né nel file né nell'app.
- Un nuovo salt casuale di 16 byte e un nonce di 12 byte per ogni file scritto.
- L'intero corpo del file è crittografato con AES-256-GCM, quindi una passphrase errata o un file danneggiato vengono rifiutati e non vengono mai decrittografati in file inutilizzabili.
- L'intestazione (formato, versione, parametri KDF, salt) è associata al tag GCM come dati autenticati aggiuntivi, in modo che un file il cui fattore di lavoro è stato ridotto non venga aperto.
Il file è in formato JSON ed è leggibile con qualsiasi editor di testo; solo il testo cifrato è opaco. Chiunque trovi il file tra cinque anni, quando l'applicazione non sarà più disponibile, potrà vedere esattamente come è stato crittografato e aprirlo con OpenSSL o qualsiasi libreria Argon2.
Formato v1 (incluso nella versione 1.0, rimane leggibile)
{
"format": "authbackup",
"version": 1,
"kdf": "PBKDF2-HMAC-SHA256",
"rounds": 600000,
"salt": "<base64, 16 bytes>",
"cipher": "AES-256-GCM",
"nonce": "<base64, 12 bytes>",
"ciphertext": "<base64>",
"tag": "<base64, 16 bytes>"
}
| Passaggio | Byte |
|---|---|
key | PBKDF2-HMAC-SHA256(passphrase as UTF-8, salt, 600000 rounds, 32 bytes) |
aad | UTF-8("authbackup:1:600000:") ‖ salt (byte di salt grezzi, non base64) |
ciphertext, tag | AES-256-GCM(key, nonce, plaintext, aad); tag di 16 byte, memorizzato separatamente |
plaintext | JSON UTF-8, chiavi ordinate: {"accounts":[…],"exportedAt":"…Z","passwords":[…],"version":1} |
Nota sulla compatibilità: Android 1.0 ha scritto una variante di v1 — kdf in minuscolo, senza chiave tag (il tag di 16 byte aggiunto al testo cifrato), senza dati aggiuntivi. Entrambe le piattaforme continuano a leggere questi file (quando il tag è assente: dividono gli ultimi 16 byte, aprono con AAD vuoto; confrontano kdf senza distinzione tra maiuscole e minuscole) ed entrambe ora scrivono solo il layout sopra.
Formato v2 (attuale; predefinito per i nuovi backup)
{
"format": "authbackup",
"version": 2,
"kdf": "Argon2id",
"memoryKiB": 65536,
"passes": 3,
"lanes": 1,
"salt": "<base64, 16 bytes>",
"cipher": "AES-256-GCM",
"nonce": "<base64, 12 bytes>",
"ciphertext": "<base64>",
"tag": "<base64, 16 bytes>"
}
| Passaggio | Byte |
|---|---|
key | Argon2id(version 0x13, passphrase as UTF-8, salt, m = 65536 KiB, t = 3, p = 1, tagLength 32, no secret, no associated data) |
aad | UTF-8("authbackup:2:argon2id:65536:3:1:") ‖ salt |
ciphertext, tag | AES-256-GCM(key, nonce, plaintext, aad); tag di 16 byte, memorizzato separatamente |
plaintext | JSON UTF-8, chiavi ordinate: {"accounts":[…],"cards":[…],"exportedAt":"…Z","passwords":[…],"version":2} |
Argon2id è l'implementazione C di riferimento (phc-winner-argon2, CC0), disponibile su entrambe le piattaforme. 64 MiB e 3 passaggi richiedono circa un secondo su un telefono attuale e ogni tentativo costa quella memoria e quel tempo su qualsiasi hardware: una caratteristica che PBKDF2 non possiede sui sistemi con GPU, ed è il motivo per cui esiste la versione 2. Un lettore ignora le chiavi che non conosce, quindi un lettore v1 a cui viene fornito un corpo v2 semplicemente non vede mai le carte.
Prova
Tre file di test vettoriali (backup v1, backup v2 e Argon2id) vengono generati da una terza implementazione, indipendente da entrambe le app (OpenSSL di Node per PBKDF2 e AES-GCM, un Argon2id di WebAssembly verificato in fase di generazione rispetto alle risposte pubblicate dall'implementazione di riferimento). Ciascuno contiene la passphrase, il salt, il nonce, il testo in chiaro, la chiave derivata, l'AAD, il testo cifrato e il tag previsti, e il file completo. I test unitari su iOS e su Android leggono gli stessi file e verificano gli stessi byte: in questo modo, un backup sigillato su una piattaforma viene dimostrato, e non presunto, che si aprirà sull'altra, e la concordanza di tutti e tre non rappresenta due copie dello stesso errore. Uno strumento complementare apre un file che un telefono ha effettivamente scritto con la stessa terza implementazione e controlla l'intestazione rispetto alle regole sopra indicate (esattamente le chiavi del formato, quindi non possono essere presenti suggerimenti o nomi; salt di 16 byte, nonce di 12 byte, tag di 16 byte memorizzati separatamente; versione 2 esattamente a 64 MiB / 3 / 1; passphrase errata rifiutata); l'esecuzione automatizzata di iOS ne scrive uno sul simulatore e lo apre in quel modo, e cerca nel contenitore dell'app del simulatore, nel contenitore del gruppo di app e nel database del portachiavi ogni password e numero di carta precompilati come UTF-8 e UTF-16 (0 risultati).
4. Modello di minaccia
| Situazione | Ciò che hanno | Ciò che ottengono |
|---|---|---|
| Telefono smarrito o rubato, bloccato | Ciò che hannoIl dispositivo, il file del database, le righe sigillate | Ciò che ottengonoTesto cifrato. La chiave di protezione si trova nella Secure Enclave/StrongBox e viene rilasciata solo dopo il blocco del dispositivo e l'inserimento di un nuovo dato biometrico o codice di accesso. La cancellazione remota dei dati del telefono (Trova il mio dispositivo) distrugge anche il materiale della chiave. |
| File di backup rubato | Ciò che hannoIl file .authbackup da un account cloud, un'e-mail, un laptop | Ciò che ottengonoUn corpo AES-256-GCM sotto una chiave derivata da una passphrase di almeno 12 caratteri, con un salt per file e Argon2id a 64 MiB × 3 passaggi (v2) o PBKDF2 a 600.000 round (v1). Nessun suggerimento, nessun nome utente, nessun elenco di account in chiaro. Ogni tentativo costa l'intera derivazione; non ci sono scorciatoie. Una passphrase robusta è l'unica difesa in questo caso, e l'applicazione lo specifica chiaramente. |
| Dispositivo rubato con schermo sbloccato | Ciò che hannoUn telefono in mano, sbloccato | Ciò che ottengonoElenco dei codici. Il vault (password, carte) è protetto dal blocco app e si blocca automaticamente al termine del timer di blocco (immediatamente / 1 min / 5 min); un valore decrittografato esiste in memoria solo finché viene visualizzato sullo schermo. Il riempimento automatico e l'esportazione in chiaro richiedono un nuovo dato biometrico anche quando l'app è aperta. Attiva il blocco app con l'opzione "Immediatamente" se questa situazione ti preoccupa. |
| Applicazione dannosa sullo stesso telefono | Ciò che hannoLa sandbox di un'altra app, gli appunti, l'accessibilità o i trucchi di sovrapposizione | Ciò che ottengonoNon può leggere i nostri file (sandboxing della piattaforma) né utilizzare la nostra chiave (la chiave è associata alla nostra identità di firma e alla presenza dell'utente). Le copie vengono eliminate dagli appunti dopo 30 secondi; su Android la copia viene contrassegnata come sensibile ed esclusa dalla cronologia degli appunti. Le schermate del vault sono impostate su FLAG_SECURE su Android (nessuno screenshot, nessuna registrazione dello schermo, vuoto nello switcher); iOS svuota l'anteprima dello switcher. La funzione di compilazione automatica su Android viene fornita solo alle app che il sistema ha verificato rispetto al dominio salvato (Digital Asset Links), quindi a un'app simile non viene offerta la tua password. |
| Pagina di phishing | Ciò che hannoUn sito che assomiglia a quello che hai salvato | Ciò che ottengonoNessun campo viene compilato automaticamente. La corrispondenza avviene tramite dominio registrabile (elenco di suffissi pubblici, incluso e aggiornato con l'app): login.example.com e example.com corrispondono, example.com.evil.net e examplep1e.com no. Il browser integrato nell'app effettua la corrispondenza allo stesso modo e compila solo il campo richiesto, verificando nuovamente l'origine di tale campo al momento della compilazione; un host senza un proprio dominio registrabile (un indirizzo IP, un semplice nome sulla rete locale) viene abbinato esattamente e senza alcuna approssimazione. iOS AutoFill aggiunge il controllo dei domini associati di Apple. Una password che devi incollare manualmente in un campo simile rappresenta comunque un rischio; l'app non può eliminarlo del tutto, ma solo evitare di fornire aiuto. |
| I nostri server | Ciò che hanno— | Ciò che ottengonoNon esiste un server dedicato al vault. AssuredAuth non gestisce account, non prevede accessi e non possiede copie del tuo vault, quindi non c'è nulla di tuo che possa essere rubato o violato dai nostri server. Due elementi, tuttavia, vengono eseguiti lato server, nessuno dei quali ha accesso al vault: una casella di posta di inoltro per l'estensione desktop, che memorizza le buste crittografate end-to-end (codici monouso, eliminati dopo la lettura; il server di inoltro non possiede mai una chiave), e i server di uscita della connessione privata opzionale, che gestiscono il traffico e non conservano registri di accesso. |
| Una citazione in giudizio o una richiesta governativa | Ciò che hannoProcedimento legale a noi indirizzato | Ciò che ottengonoNulla da consegnare: non possediamo alcuna cassaforte, alcuna chiave, alcuna frase di accesso e alcun backup. Possiamo essere costretti ad affermarlo; non possiamo essere costretti a produrre ciò che non esiste. |
5. Appunti, schermate e memoria
- La funzione Copia inserisce il valore negli appunti per 30 secondi, quindi lo cancella se è ancora presente. Su Android, l'elemento copiato è contrassegnato come EXTRA_IS_SENSITIVE, quindi il sistema lo nasconde dall'anteprima e dalla cronologia degli appunti; su iOS, l'elemento copiato è solo locale (non viene trasferito ad altri dispositivi tramite Handoff).
- Le schermate del Vault (Password, Password, Carte, Carta, i fogli delle passphrase, l'esportazione in testo semplice) impostano FLAG_SECURE su Android. iOS non ha un flag equivalente; l'app oscura la sua miniatura nello switcher delle app e i valori sono nascosti dietro un interruttore a forma di occhio per impostazione predefinita.
- I valori decrittografati risiedono in memoria solo finché vengono visualizzati sullo schermo e vengono eliminati quando questo scompare o l'app si blocca. La chiave dati viene decodificata per ogni richiesta e non viene memorizzata nella cache dopo il blocco.
- È disponibile l'esportazione in testo semplice (quindi puoi sempre uscire) ed è protetta da una schermata di conferma e da una nuova autenticazione biometrica; anche la schermata è protetta da FLAG_SECURE.
6. Completamento automatico: cosa viene compilato e cosa no
| Dove | Password | Carte |
|---|---|---|
| iOS: Safari e app (estensione di compilazione automatica) | PasswordSì, dopo un nuovo Face ID / Touch ID / codice di accesso nell'estensione (LAContext), e solo per il dominio registrabile per cui è stata salvata la voce, con il controllo dei domini associati di Apple per le app | CarteNo. Il riempimento automatico delle carte in Safari è un'esclusiva di Apple; la schermata della carta dice "Compila nel browser AssuredAuth e con Copia" e non promette altro. |
| Android: app e Chrome (AutofillService) | PasswordSì, autenticazione per dataset: il sistema mostra BiometricPrompt prima del riempimento; il pacchetto dell'app viene abbinato solo quando Digital Asset Links lo collega al dominio salvato. | CarteSì, i suggerimenti creditCardNumber, creditCardExpiration* e creditCardSecurityCode, stesso gate biometrico |
| Il browser AssuredAuth (entrambe le piattaforme) | PasswordSì, tramite dominio registrabile — un host senza alcuna corrispondenza propria esattamente — nel frame richiesto, biometrico prima del riempimento | CarteSì, tramite rilevamento sul campo, biometrico prima del riempimento |
| Pulsanti Copia | PasswordDietro il blocco app, appunti di 30 secondi | CarteNumero, data di scadenza, CVC (stesse regole) |
Nulla si riempie su un ospite identico. Nulla si riempie senza i dati biometrici.
7. Ciò che non accade mai
Nessun server di vault. Nessuna analisi che includa un campo del vault. Nessuna esportazione in testo semplice senza un foglio di conferma e una nuova acquisizione biometrica. Nessun SDK di terze parti caricato su una schermata del vault. Nessuno screenshot di una schermata del vault. Nessun suggerimento per la passphrase. Nessuna registrazione dei valori, in nessuna build.
8. Ciò da cui non possiamo proteggerci
Una passphrase così debole da poter essere indovinata. Un telefono il cui sistema operativo è compromesso alla radice (un dispositivo jailbroken o con root può mentire all'app su tutto quanto sopra). Una persona che viene spiata mentre digita. Malware sul desktop in cui si incolla. Lo diciamo affinché l'elenco di cui sopra venga letto per quello che è: le cose che un design può eliminare, eliminate.
9. Stato della revisione
Questo progetto è stato testato con unit test confrontandolo con soluzioni note pubblicate su entrambe le piattaforme e con i propri vettori multipiattaforma. Il proprietario ha in programma una revisione esterna prima che il vault venga pubblicizzato nel negozio; fino a quando non sarà avvenuta, questo documento lo indicherà.
10. Dove viene eseguito cosa
Nessun dato contenuto nel vault esce dal telefono, ma alcune funzionalità correlate vengono eseguite sui computer di altre persone. Questo è l'elenco e il contenuto di ciascuna funzionalità; i flussi di dati sono descritti nell'informativa sulla privacy disponibile all'indirizzo https://assuredauth.com/privacy.
- Google Cloud/Firebase: la casella di posta di inoltro per l'estensione desktop (buste crittografate end-to-end, eliminate dopo la lettura), i token push, lo stato degli acquisti e i messaggi inviati tramite il modulo di contatto.
- Vercel — assuredauth.com, le sue pagine e le piccole funzioni che si celano dietro di esse.
- Vultr: i server di uscita della connessione privata. Il traffico passa attraverso di essi; nulla viene memorizzato.
- Apple e Google Play: acquisti e abbonamenti nei rispettivi store.
- PostHog — analisi dei prodotti: conteggio di ciò che viene utilizzato, senza alcun collegamento a un'identità.
- RevenueCat — lo stato di un abbonamento: attivo o scaduto, e il piano di abbonamento.
Ciascun prodotto contiene quanto indicato nella sua linea e nulla proveniente dal caveau. L'elenco cambia quando cambia il prodotto, e questa sezione cambia di conseguenza.
Segnalazione di una debolezza
Se ritieni di aver trovato una debolezza in qualcosa di quanto descritto qui, scrivi a hello@assuredauth.com con oggetto "Sicurezza". Indica la piattaforma, la versione dell'app e i passaggi; basta una prova che usi i tuoi dati, e ti chiediamo di non fare test sui dati di altre persone. Non offriamo una chiave PGP; se una segnalazione non dovrebbe viaggiare in email in chiaro, dillo in un primo messaggio e troveremo un'altra via.
In cambio, vi promettiamo di darvi riscontro entro tre giorni lavorativi, di tenervi informati sui progressi, di correggere eventuali inesattezze prima della pubblicazione e di citarvi qui, se lo desiderate. Non intraprenderemo azioni legali in merito a ricerche condotte in buona fede nell'ambito di quanto indicato di seguito.
Sono inclusi nell'ambito di applicazione: le app per iOS e Android, le app per Apple Watch, l'estensione per desktop, assuredauth.com e la sua API. Sono esclusi dall'ambito di applicazione: l'App Store e Google Play, i fornitori sopra elencati, qualsiasi forma di ingegneria sociale e gli attacchi denial of service.
Al momento non è prevista alcuna ricompensa. Una segnalazione viene esaudita con una soluzione e un ringraziamento, non con un compenso in denaro.