I .class
file Java possono essere decompilati abbastanza facilmente. Come posso proteggere il mio database se devo utilizzare i dati di accesso nel codice?
I .class
file Java possono essere decompilati abbastanza facilmente. Come posso proteggere il mio database se devo utilizzare i dati di accesso nel codice?
Risposte:
Non inserire mai password nel codice. Questo è stato recentemente menzionato nella Top 25 degli errori di programmazione più pericolosi :
L'hardcoding di un account e di una password segreti nel tuo software è estremamente conveniente, per i tecnici esperti. Se la password è la stessa in tutto il software, ogni cliente diventa vulnerabile quando la password diventa inevitabilmente nota. E poiché è hard-coded, è un enorme problema da risolvere.
È necessario memorizzare le informazioni di configurazione, comprese le password, in un file separato che l'applicazione legge all'avvio. Questo è l'unico vero modo per evitare che la password venga persa a causa della decompilazione (non compilarla mai nel binario per cominciare).
Per ulteriori informazioni su questo errore comune, puoi leggere l' articolo CWE-259 . L'articolo contiene una definizione più completa, esempi e molte altre informazioni sul problema.
In Java, uno dei modi più semplici per farlo è utilizzare la classe Preferenze. È progettato per memorizzare tutti i tipi di impostazioni del programma, alcune delle quali potrebbero includere un nome utente e una password.
import java.util.prefs.Preferences;
public class DemoApplication {
Preferences preferences =
Preferences.userNodeForPackage(DemoApplication.class);
public void setCredentials(String username, String password) {
preferences.put("db_username", username);
preferences.put("db_password", password);
}
public String getUsername() {
return preferences.get("db_username", null);
}
public String getPassword() {
return preferences.get("db_password", null);
}
// your code here
}
Nel codice sopra, puoi chiamare il setCredentials
metodo dopo aver mostrato una finestra di dialogo che chiede il nome utente e la password. Quando è necessario connettersi al database, è possibile utilizzare semplicemente i metodi getUsername
e getPassword
per recuperare i valori memorizzati. Le credenziali di accesso non saranno codificate nei tuoi file binari, quindi la decompilazione non rappresenterà un rischio per la sicurezza.
Nota importante: i file delle preferenze sono solo file XML di testo semplice. Assicurati di adottare le misure appropriate per impedire agli utenti non autorizzati di visualizzare i file raw (autorizzazioni UNIX, autorizzazioni Windows, ecc.). In Linux, almeno, questo non è un problema, perché la chiamata Preferences.userNodeForPackage
creerà il file XML nella directory home dell'utente corrente, che comunque non è leggibile da altri utenti. In Windows, la situazione potrebbe essere diversa.
Note più importanti: ci sono state molte discussioni nei commenti di questa risposta e di altri su quale sia l'architettura corretta per questa situazione. La domanda originale in realtà non menziona il contesto in cui viene utilizzata l'applicazione, quindi parlerò delle due situazioni a cui riesco a pensare. Il primo è il caso in cui la persona che utilizza il programma conosce già (ed è autorizzata a conoscere) le credenziali del database. Il secondo è il caso in cui tu, lo sviluppatore, stai cercando di mantenere segrete le credenziali del database dalla persona che utilizza il programma.
Primo caso: l'utente è autorizzato a conoscere le credenziali di accesso al database
In questo caso, la soluzione che ho menzionato sopra funzionerà. La Preference
classe Java memorizzerà il nome utente e la password in testo normale, ma il file delle preferenze sarà leggibile solo dall'utente autorizzato. L'utente può semplicemente aprire il file XML delle preferenze e leggere le credenziali di accesso, ma questo non è un rischio per la sicurezza perché l'utente conosceva le credenziali per cominciare.
Secondo caso: tentativo di nascondere le credenziali di accesso all'utente
Questo è il caso più complicato: l'utente non dovrebbe conoscere le credenziali di accesso ma deve comunque accedere al database. In questo caso, l'utente che esegue l'applicazione ha accesso diretto al database, il che significa che il programma deve conoscere in anticipo le credenziali di accesso. La soluzione che ho menzionato sopra non è appropriata per questo caso. È possibile memorizzare le credenziali di accesso al database in un file delle preferenze, ma l'utente sarà in grado di leggere quel file, poiché sarà il proprietario. In effetti, non esiste davvero un buon modo per utilizzare questa custodia in modo sicuro.
Caso corretto: utilizzo di un'architettura multilivello
Il modo corretto per farlo è disporre di un livello intermedio, tra il server del database e l'applicazione client, che autentichi i singoli utenti e consenta di eseguire un insieme limitato di operazioni. Ogni utente avrebbe le proprie credenziali di accesso, ma non per il server del database. Le credenziali consentirebbero l'accesso al livello intermedio (il livello della logica aziendale) e sarebbero diverse per ogni utente.
Ogni utente avrebbe il proprio nome utente e password, che potrebbero essere memorizzati localmente in un file delle preferenze senza alcun rischio per la sicurezza. Questa è chiamata architettura a tre livelli (i livelli sono il server di database, il server della logica di business e l'applicazione client). È più complesso, ma è davvero il modo più sicuro per fare questo genere di cose.
L'ordine di base delle operazioni è:
getInventoryList
.Notare che durante l'intero processo, l'applicazione client non si connette mai direttamente al database . Il livello di logica aziendale riceve una richiesta da un utente autenticato, elabora la richiesta del client per un elenco di inventario e solo successivamente esegue una query SQL.
Metti la password in un file che l'applicazione leggerà. NON incorporare MAI password in un file sorgente. Periodo.
Ruby ha un modulo poco conosciuto chiamato DBI :: DBRC per tale utilizzo. Non ho dubbi che Java abbia un equivalente. Comunque non è difficile scriverne uno.
Stai scrivendo un'applicazione web? In tal caso, utilizzare JNDI per configurarlo esternamente all'applicazione. Una panoramica è disponibile qui :
JNDI fornisce a un'applicazione un modo uniforme per trovare e accedere a servizi remoti sulla rete. Il servizio remoto può essere qualsiasi servizio aziendale, incluso un servizio di messaggistica o un servizio specifico dell'applicazione, ma, ovviamente, un'applicazione JDBC è interessata principalmente a un servizio di database. Una volta che un oggetto DataSource è stato creato e registrato con un servizio di denominazione JNDI, un'applicazione può utilizzare l'API JNDI per accedere a tale oggetto DataSource, che può quindi essere utilizzato per connettersi all'origine dati che rappresenta.
Qualunque cosa tu faccia, le informazioni sensibili verranno archiviate in qualche file da qualche parte. Il tuo obiettivo è renderlo il più difficile possibile. Quanto di questo puoi ottenere dipende dal tuo progetto, dalle esigenze e dallo spessore del portafoglio della tua azienda.
Il modo migliore è non memorizzare le password ovunque. Ciò si ottiene utilizzando le funzioni hash per generare e memorizzare gli hash delle password:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
Gli algoritmi hash sono funzioni unidirezionali. Trasformano qualsiasi quantità di dati in una "impronta digitale" di lunghezza fissa che non può essere annullata. Hanno anche la proprietà che se l'input cambia anche di un piccolo bit, l'hash risultante è completamente diverso (vedi l'esempio sopra). Questo è ottimo per proteggere le password, perché vogliamo memorizzare le password in una forma che le protegga anche se il file delle password stesso è compromesso, ma allo stesso tempo, dobbiamo essere in grado di verificare che la password di un utente sia corretta.
Nota non correlata: ai vecchi tempi di Internet, quando si faceva clic sul collegamento "Ho dimenticato la password", i siti Web inviavano tramite posta elettronica la password in testo normale. Probabilmente li stavano archiviando in un database da qualche parte. Quando gli hacker hanno ottenuto l'accesso al loro database, avrebbero ottenuto l'accesso a tutte le password. Poiché molti utenti avrebbero utilizzato la stessa password in più siti Web, questo era un enorme problema di sicurezza. Fortunatamente, oggigiorno questa non è una pratica comune.
Ora arriva la domanda: qual è il modo migliore per memorizzare le password? Considererei questa soluzione (servizio di autenticazione e gestione utenti stormpath) dannatamente ideale:
Ovviamente non sei Google o una banca, quindi questa è una soluzione eccessiva per te. Ma poi arriva la domanda: quanta sicurezza richiede il tuo progetto, quanto tempo e denaro hai?
Per molte applicazioni, sebbene non sia consigliato, memorizzare la password hardcoded nel codice potrebbe essere una soluzione abbastanza buona. Tuttavia, aggiungendo facilmente un paio di passaggi extra di sicurezza dall'elenco sopra, puoi rendere la tua applicazione molto più sicura.
Ad esempio, supponiamo che il passaggio 1 non sia una soluzione accettabile per il tuo progetto. Non vuoi che gli utenti inseriscano la password ogni volta o non vuoi / non hai nemmeno bisogno che gli utenti conoscano la password. Hai ancora informazioni sensibili da qualche parte e vuoi proteggerle. Hai una semplice applicazione, non c'è un server per archiviare i tuoi file o questo è troppo fastidioso per il tuo progetto. L'applicazione viene eseguita in ambienti in cui non è possibile archiviare i file in modo sicuro. Questo è uno dei casi peggiori, ma comunque con qualche misura di sicurezza aggiuntiva puoi avere una soluzione molto più sicura. Ad esempio, è possibile archiviare le informazioni riservate in un file e crittografare il file. È possibile inserire la chiave privata di crittografia nel codice. Puoi offuscare il codice, quindi rendi un po 'più difficile per qualcuno decifrarlo.questo collegamento . (Voglio avvertirti ancora una volta che questo non è sicuro al 100%. Un hacker intelligente con le giuste conoscenze e strumenti può hackerarlo. Ma in base alle tue esigenze e necessità, questa potrebbe essere una soluzione abbastanza buona per te).
Questa domanda mostra come archiviare password e altri dati in un file crittografato: Crittografia basata su password AES Java a 256 bit
MD5 è un algoritmo hash, non un algoritmo di crittografia, in breve non puoi recuperare ciò che hai hash, puoi solo confrontare. Idealmente dovrebbe essere utilizzato quando si memorizzano le informazioni di autenticazione dell'utente e non il nome utente e la password del database. db username e pwd dovrebbero essere crittografati e conservati in un file di configurazione, per fare il minimo.