Come posso proteggere il nome utente e la password MySQL dalla decompilazione?


87

I .classfile Java possono essere decompilati abbastanza facilmente. Come posso proteggere il mio database se devo utilizzare i dati di accesso nel codice?


Spero non ti dispiaccia se ho riclassificato la tua domanda. Ho rimosso "nome utente" e "password" e aggiunto "reverse engineering" e "decompilazione". Penso che siano più descrittivi degli originali. Ottima domanda sui fondamentali, comunque!
William Brendel

6
Nota che il fatto che stai usando Java non è realmente rilevante qui. Avere password hardcoded in qualsiasi lingua è problematico più o meno allo stesso modo ("strings thebinary" mostra le costanti di stringa anche nei programmi C).
Joachim Sauer

@saua: Vero, ma forse qualcuno pubblicherà un codice di esempio su come disaccoppiare nomi utente e password in Java. Potrei anche farlo io stesso se ne avrò il tempo.
William Brendel

1
Ho notato che molte risposte pensano che tu stia cercando di nascondere il nome utente / password a un utente non autorizzato mentre l'utente che esegue l'app è ok. Credo che tu voglia nascondere la password a TUTTI . Si prega di chiarirlo nella domanda.
pek

1
Ad esempio, supponiamo che le credenziali vengano utilizzate per connettersi a un server a cui nessun altro oltre all'applicazione può accedere.
pek

Risposte:


123

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 setCredentialsmetodo 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 getUsernamee getPasswordper 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.userNodeForPackagecreerà 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 Preferenceclasse 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 è:

  1. Il client si autentica con il livello di logica aziendale utilizzando il nome utente / password personali dell'utente. Il nome utente e la password sono noti all'utente e non sono correlati in alcun modo alle credenziali di accesso al database.
  2. Se l'autenticazione ha esito positivo, il client effettua una richiesta al livello di logica aziendale chiedendo alcune informazioni dal database. Ad esempio, un inventario di prodotti. Notare che la richiesta del client non è una query SQL; è una chiamata di procedura remota come getInventoryList.
  3. Il livello di logica aziendale si connette al database e recupera le informazioni richieste. Il livello di logica aziendale è incaricato di formare una query SQL sicura in base alla richiesta dell'utente. Tutti i parametri della query SQL devono essere disinfettati per prevenire attacchi di SQL injection.
  4. Il livello di logica aziendale invia l'elenco di inventario all'applicazione client.
  5. Il cliente mostra l'elenco dell'inventario all'utente.

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.


4
In che modo esattamente questo impedisce a qualcuno di ottenere il nome utente / password? Allora non puoi leggerlo dal file?
Joe Phillips

Come ho detto nella mia risposta, se le autorizzazioni del file sono impostate correttamente, solo l'utente che esegue il programma ha accesso in lettura a quel file delle preferenze. Negli ambienti UNIX, questa operazione viene eseguita automaticamente. Windows potrebbe richiedere passaggi aggiuntivi (non ne sono davvero sicuro, dato che non uso molto Windows).
William Brendel

Penso che l'idea sia che l'utente che esegue l'app non sia quello da cui stai cercando di impedirla. In tal caso, dovresti crittografarlo.
Michael Haren

Sì, Michael ha ragione. Essenzialmente l'idea è che tu conosca già il nome utente / password, quindi non è necessario nasconderlo a te stesso. Tuttavia, verrà nascosto agli altri utenti tramite i permessi dei file.
William Brendel

7
Se stai distribuendo (esempio) un'applicazione di modifica del database a un utente e non vuoi che conoscano il nome utente e la password del database, allora hai progettato la soluzione in modo sbagliato e il software client dovrebbe comunicare con un server (tramite ad esempio, un servizio web) che fa le cose del DB.
JeeBee

15

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.


7
Sebbene ciò semplifichi leggermente la modifica delle password in un secondo momento, non risolve il problema di sicurezza di base.
Brian Knoblauch,

Sì lo fa. Vedi anche la risposta di William Brendel.
Keltia

1
Il metodo che io e Keltia abbiamo indicato è il modo accettato di affrontare questo problema. Separare le credenziali di accesso dal codice compilato è una delle pratiche di sicurezza del software più basilari. Mettere le credenziali di accesso in un file separato è un modo efficace per ottenere ciò.
William Brendel

Inoltre, il fatto che le informazioni di configurazione siano in un file di testo normale dovrebbe essere annullato dalle restrizioni del sistema operativo. Ad esempio, in UNIX, il file di testo in chiaro dovrebbe essere di proprietà dell'utente che esegue il programma e avere i permessi 0600, quindi solo il proprietario può leggerlo.
William Brendel

4
OK, quindi il file può essere letto solo dall'utente che esegue il programma. Grande. Questo non risolve nulla. :-) Io, l'utente da cui stiamo cercando di mantenere segreta la password, posso leggerla facilmente come l'app ...
Brian Knoblauch

3

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.


il collegamento fornito è pessimo
James Oravec

2

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:

  1. Il tuo utente inserisce le credenziali e questo viene convalidato rispetto all'hash della password
  2. Gli hash delle password vengono generati e archiviati, non le password
  3. Gli hash vengono eseguiti più volte
  4. Gli hash vengono generati utilizzando un sale generato in modo casuale
  5. Gli hash vengono crittografati con una chiave privata
  6. La chiave privata è archiviata in un luogo fisicamente diverso dagli hash
  7. Le chiavi private sono aggiornate in base al tempo
  8. Gli hash crittografati sono suddivisi in blocchi
  9. Questi blocchi vengono archiviati in posizioni fisicamente separate

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).



0

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.


Ho sentito di persone che generano tutte le possibili combinazioni di stringhe e memorizzano i corrispondenti hash MD5. Quindi, quando trovano l'hash MD5 di qualcuno, trovano semplicemente l'hash che hanno memorizzato e ottengono la stringa corrispondente.
Nav
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.