Come proteggere le password del database in PHP?


404

Quando un'applicazione PHP effettua una connessione al database, ovviamente deve generalmente passare un login e una password. Se sto usando un unico login con autorizzazione minima per la mia applicazione, il PHP deve sapere che login e password da qualche parte. Qual è il modo migliore per proteggere quella password? Sembra che scriverlo nel codice PHP non sia una buona idea.


1
Per essere totalmente sicuri, dovrai impostare una connessione ssl, altrimenti chiunque sulla tua rete potrà ancora annusare la password che digiti.
Charles Ma,

1
Intendi le password dell'utente o la password del database utilizzate nella stringa di connessione?
Ozgur Ozcitak,

4
Password del database utilizzata nella stringa di connessione. Grazie!
user18359

Risposte:


238

Diverse persone hanno letto male questo come una domanda su come archiviare le password in un database. Questo è sbagliato. Si tratta di come memorizzare la password che consente di accedere al database.

La solita soluzione è spostare la password dal codice sorgente in un file di configurazione. Quindi lasciare l'amministrazione e la protezione del file di configurazione agli amministratori di sistema. In questo modo gli sviluppatori non hanno bisogno di sapere nulla sulle password di produzione e non c'è traccia della password nel controllo del codice sorgente.


8
Grazie. Se lo capisco correttamente, il file php avrà quindi un'inclusione nel file di configurazione, permettendogli di usare la password. ad esempio, creo un file chiamato 'app1_db_cfg.php' che memorizza login, pword e nome db. Quindi la mia pagina application.php include 'app1_db_cfg.php' e sono in affari!
user18359

28
Sono d'accordo che la configurazione deve essere adeguatamente protetta. Tuttavia, sapere come farlo è compito degli amministratori di sistema, non degli sviluppatori. Non sono d'accordo sul valore della crittografia avanzata in questo caso. Se non riesci a proteggere il tuo file di configurazione, cosa ti fa pensare di poter proteggere le tue chiavi?
user11318,

10
Preferisco utilizzare un account di database a cui è consentito accedere al database solo dal server Web. E poi non mi preoccupo di crittografare la configurazione, la memorizzo solo al di fuori del web root.
gnud,

11
Uso una variabile d'ambiente apache per impostare il percorso in modo che anche il percorso del file sia sconosciuto nel codice sorgente. Ciò consente anche di avere una password diversa per lo sviluppo e la produzione in base alle impostazioni di Apache sul server
Geedew,

15
Tieni presente che anche i file archiviati al di fuori della directory accessibile dal web devono essere letti dallo script che li utilizza. Se qualcuno include quel file, quindi scarica i dati dal file, vedrà la password.
Rick Mac Gillis,

104

Se stai ospitando sul server di qualcun altro e non hai accesso al di fuori della tua webroot, puoi sempre mettere la tua password e / o connessione al database in un file e quindi bloccare il file usando un .htaccess:

<files mypasswdfile>
order allow,deny
deny from all
</files>

3
Grazie, era esattamente quello che stavo cercando.
David Gladfelter,

28
Sicuramente, ma se qualcuno ha accesso alla shell, l'intero account è stato comunque compromesso.
Kellen,

4
Questa è una cattiva pratica perché potresti accidentalmente impegnare le tue credenziali in un repository.
Porlune,

2
@Ankit: se per un non amichevole è possibile caricare un file sul server ed eseguirlo, il server non è configurato correttamente.
Kellen,

6
@Porlune: gli sviluppatori dovrebbero fare in modo che il loro sistema di controllo della versione ignori il file della password, cioè usando un .gitignore. Sì, è necessario prestare attenzione ai file che contengono dati sensibili.
Kellen,

45

Il modo più sicuro è non avere affatto le informazioni specificate nel tuo codice PHP.

Se stai usando Apache questo significa impostare i dettagli della connessione nel tuo file httpd.conf o file host virtuale. Se lo fai puoi chiamare mysql_connect () senza parametri, il che significa che PHP non produrrà mai le tue informazioni.

Ecco come si specificano questi valori in quei file:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

Quindi apri la tua connessione mysql in questo modo:

<?php
$db = mysqli_connect();

O così:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));

1
Controlla i valori corretti di ini_get ('valori predefiniti') php.net/manual/en/class.mysqli.php
Val

4
sì, ma qualsiasi utente (o un hacker che abusa di script php scritti male) può leggere la password tramite ini_get().
Marki555,

1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()Come gestisci questo?
tonix,

2
Marki555 sta dicendo che un utente malintenzionato che può eseguire il codice PHP può anche chiamare funzioni PHP, il che è ovviamente vero e impossibile fare qualcosa. Vorrei anche aggiungere che non seguo più personalmente il consiglio che do in questa risposta, ma invece uso le variabili di ambiente. Il concetto è simile però: non memorizzare le tue credenziali nel codice, ma iniettarle in qualche modo. Non importa se usi ini_get()o getenv().
Lars Nyström,

2
@DeepBlue Se puoi iniettare ini_get () puoi anche iniettare file_get_contents (anypath). Fintanto che php ha un modo per ottenere la password, anche qualsiasi codice dannoso.
varesa,

40

Memorizzarli in un file esterno alla radice Web.


29
E anche, come menzionato altrove, al di fuori del controllo del codice sorgente.
Frank Farmer,

6
saremmo in grado di includerlo? ad esempio in PHP possiamo fare include('../otherDirectory/configfile.conf')?
mtk,

1
Stai tutti suggerendo di archiviare le credenziali al di fuori di wwwroot. Ok, capisco il background di sicurezza. Ma come dovrebbe essere archiviato nel controllo versione quindi (esempio di configurazione)? Di solito wwwroot è la radice di git repo, quindi se c'è qualcosa al di fuori - sarà al di fuori di VC. Immagina che un nuovo sviluppatore stia cercando di creare un'istanza locale per lo sviluppo: come dovrebbe conoscere la magia come "prendere questo file, copiarlo all'esterno e compilarlo"?
Il padrino

@TheGodfather L'idea è che un nuovo sviluppatore dovrebbe avere le proprie credenziali per il proprio ambiente di sviluppo. Anche se è una buona pratica avere un readme con istruzioni o commenti nel codice che indica come configurarlo (ma non i dati effettivi).
PhoneixS,

@TheGodfather, file readme?
Pacerier

35

Per sistemi estremamente sicuri crittografiamo la password del database in un file di configurazione (che è protetto dall'amministratore di sistema). All'avvio dell'applicazione / server l'applicazione richiede all'amministratore di sistema la chiave di decodifica. La password del database viene quindi letta dal file di configurazione, decrittografata e archiviata in memoria per uso futuro. Non è ancora sicuro al 100% poiché è memorizzato nella memoria decrittografata, ma a un certo punto devi chiamarlo 'abbastanza sicuro'!


85
cosa succede se l'amministratore muore?
Radu Murzea,

36
@RaduMurzea è ridicolo. Quando hai saputo della morte di Sys Admins? Sono come McDonalds, appaiono e scompaiono dal nulla!
ILikeTacos,

13
@Radu Murzea Hai solo 2 o più amministratori, quindi hai la parità come un array di raid. Le possibilità che si verifichi più di un'unità alla volta sono molto più basse.
element11

5
che dire del riavvio dei server? Che dire del tempo necessario per riattivare l'amministratore per indurli a digitare la password in..etc.etc. lol
John Hunt,

1
Non sono sicuro di cosa intendi per "archiviato in memoria". Le app Web PHP generalmente non memorizzano nulla in memoria per un tempo superiore al tempo necessario per rispondere a una singola richiesta di visualizzazione di una pagina.
bdsl,

15

Questa soluzione è generale, in quanto è utile per applicazioni sia open che closed source.

  1. Crea un utente del sistema operativo per la tua applicazione. Vedi http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Creare una variabile di ambiente del sistema operativo (non di sessione) per quell'utente, con la password
  3. Esegui l'applicazione come quell'utente

vantaggi:

  1. Non controllerai le tue password nel controllo del codice per sbaglio, perché non puoi
  2. Non rovinerai accidentalmente le autorizzazioni dei file. Bene, potresti, ma non influenzerà questo.
  3. Può essere letto solo dal root o da quell'utente. Root può comunque leggere tutti i file e le chiavi di crittografia.
  4. Se usi la crittografia, come stai conservando la chiave in modo sicuro?
  5. Funziona x-platform
  6. Assicurarsi di non passare envvar a processi figlio non attendibili

Questo metodo è suggerito da Heroku, che ha molto successo.


11

se è possibile creare la connessione al database nello stesso file in cui sono archiviate le credenziali. Inline le credenziali nell'istruzione connect.

mysql_connect("localhost", "me", "mypass");

Altrimenti è meglio disinserire le credenziali dopo l'istruzione connect, poiché le credenziali che non sono in memoria, non possono essere lette dalla memoria ;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  

9
Se qualcuno ha accesso alla memoria, sei comunque fregato. Questa è inutile falsa sicurezza. Al di fuori del webroot (o almeno protetto da un .htaccess se non si ha accesso al di sopra del webroot) è l'unica opzione sicura.
uliwitness,

2
@uliwitness - È come dire che solo perché qualcuno può tagliare la serratura del centro operativo della tua rete con una torcia in acetilene significa che la porta è anche una falsa sicurezza. Mantenere sempre le informazioni sensibili vincolate al più stretto ambito possibile ha sempre senso.
Luke A. Leber,

1
Che ne dici di echo $ db_user o di stampare $ db_pass? Anche gli sviluppatori dello stesso team non dovrebbero essere in grado di capire le credenziali di produzione. Il codice non deve contenere nulla stampabile sulle informazioni di accesso.
Mohammed Joraid,

8

Le tue scelte sono un po 'limitate poiché come dici hai bisogno della password per accedere al database. Un approccio generale è quello di memorizzare il nome utente e la password in un file di configurazione separato anziché nello script principale. Quindi assicurati di memorizzarlo all'esterno dell'albero web principale. Questo era se c'è un problema di configurazione web che lascia i tuoi file php semplicemente visualizzati come testo anziché essere eseguiti non hai esposto la password.

Diverso da quello che sei sulle linee giuste con un accesso minimo per l'account in uso. Aggiungi a quello

  • Non utilizzare la combinazione di nome utente / password per nient'altro
  • Configurare il server database per accettare connessioni dall'host Web solo per quell'utente (localhost è ancora migliore se il DB si trova sullo stesso computer) In questo modo, anche se le credenziali sono esposte, non sono utili a nessuno a meno che non abbiano altro accesso al macchina.
  • Offusca la password (anche ROT13 lo farà) non creerà molta difesa se alcuni accedono al file, ma almeno impedirà la visualizzazione casuale di esso.

Peter


8

Se stai usando PostgreSQL, cerca ~/.pgpassautomaticamente le password. Vedere il manuale per ulteriori informazioni.


8

In precedenza abbiamo archiviato l'utente / passaggio DB in un file di configurazione, ma da allora abbiamo raggiunto la modalità paranoica, adottando una politica di difesa in profondità .

Se l'applicazione è compromessa, l'utente avrà accesso in lettura al file di configurazione e quindi è possibile che un cracker legga queste informazioni. I file di configurazione possono anche essere bloccati nel controllo versione o copiati nei server.

Siamo passati alla memorizzazione di user / pass nelle variabili di ambiente impostate in Apache VirtualHost. Questa configurazione è leggibile solo da root - si spera che l'utente Apache non stia eseguendo come root.

Il problema è che ora la password è in una variabile PHP globale.

Per mitigare questo rischio abbiamo le seguenti precauzioni:

  • La password è criptata Estendiamo la classe PDO per includere la logica per decrittografare la password. Se qualcuno legge il codice in cui stabiliamo una connessione, non sarà ovvio che la connessione viene stabilita con una password crittografata e non con la password stessa.
  • La password crittografata viene spostata dalle variabili globali in una variabile privata L'applicazione lo fa immediatamente per ridurre la finestra in cui il valore è disponibile nello spazio globale.
  • phpinfo()è disabilitato. PHPInfo è un obiettivo semplice per ottenere una panoramica di tutto, comprese le variabili di ambiente.

6

Inserire la password del database in un file, renderlo di sola lettura per l'utente che serve i file.

A meno che tu non abbia qualche modo per consentire al processo del server php di accedere al database, questo è praticamente tutto ciò che puoi fare.


5

Se stai parlando della password del database, al contrario della password proveniente da un browser, la pratica standard sembra essere quella di mettere la password del database in un file di configurazione PHP sul server.

Devi solo assicurarti che il file php contenente la password abbia le autorizzazioni appropriate su di esso. Cioè dovrebbe essere leggibile solo dal server web e dal tuo account utente.


1
Sfortunatamente il file di configurazione di PHP può essere letto da phpinfo () e se qualcuno dovesse lasciare qualche script di test dietro un fortunato aggressore sarebbe in grado di leggere la password. È probabilmente preferibile lasciare la password di connessione in un file all'esterno della radice del server Web. Quindi l'unico modo per accedervi è con una shell o eseguendo un codice arbitrario, ma in quello scenario si perde comunque tutta la sicurezza.
MarioVilas,

5

Metterlo in un file di configurazione da qualche parte è il modo in cui viene fatto di solito. Assicurati solo di:

  1. impedire l'accesso al database da qualsiasi server esterno alla rete,
  2. fare attenzione a non mostrare accidentalmente la password agli utenti (in un messaggio di errore o tramite file PHP accidentalmente serviti come HTML, eccetera).

5

Lo abbiamo risolto in questo modo:

  1. Utilizzare memcache sul server, con connessione aperta da un altro server password.
  2. Salva in memcache la password (o anche tutto il file password.php crittografato) più la chiave di decrittografia.
  3. Il sito web chiama la chiave memcache che contiene la passphrase del file password e decodifica in memoria tutte le password.
  4. Il server delle password invia un nuovo file di password crittografato ogni 5 minuti.
  5. Se si utilizza password.php crittografato sul progetto, si effettua un controllo, che controlla se questo file è stato toccato esternamente o visualizzato. In questo caso, è possibile pulire automaticamente la memoria e chiudere il server per l'accesso.

4

Un ulteriore trucco è utilizzare un file di configurazione separato PHP che assomigli a quello:

<?php exit() ?>

[...]

Plain text data including password

Ciò non impedisce di impostare correttamente le regole di accesso. Ma nel caso in cui il tuo sito web venga hackerato, un "richiede" o un "include" uscirà dallo script in prima linea, quindi è ancora più difficile ottenere i dati.

Tuttavia, non lasciare mai i file di configurazione in una directory a cui è possibile accedere tramite il Web. Dovresti avere una cartella "Web" contenente il tuo codice controler, css, immagini e js. È tutto. Tutto il resto va in cartelle offline.


ma come fa lo script php a leggere le credenziali archiviate nel file?
Christopher Mahan,

3
Si utilizza fopen (), come per un normale file di testo.
e-soddisfa il

2
@ e-satis ok impedirà agli hacker di fare require/ includema come impedire di farlo fopen?
dmnc,

"Questo non ti impedisce di impostare correttamente le regole di accesso"
e-satis

@ e-satis, questo è abbastanza intelligente. mi chiedo perché nessuno ci abbia pensato. Tuttavia , è ancora vulnerabile al problema della copia dell'editor. feross.org/cmsploit
Pacerier

4

Il modo migliore è di non memorizzare affatto la password!
Ad esempio, se si utilizza un sistema Windows e ci si connette a SQL Server, è possibile utilizzare l'autenticazione integrata per connettersi al database senza password, utilizzando l'identità del processo corrente.

Se è necessario connettersi con una password, crittografarla innanzitutto , utilizzando una crittografia avanzata (ad esempio utilizzando AES-256, quindi proteggere la chiave di crittografia o utilizzare la crittografia asimmetrica e fare in modo che il sistema operativo protegga il certificato), quindi memorizzarlo in un file di configurazione (esterno alla directory Web) con ACL forti .


3
Inutile crittografare nuovamente la password . Qualcuno che potrebbe ottenere la password non crittografata può anche ottenere qualsiasi passphrase necessaria per decrittografare la password. Tuttavia, utilizzare ACL e .htaccess è una buona idea.
uliwitness,

2
@uliwitness Penso che potresti aver frainteso - cosa intendi con "crittografare di nuovo "? È solo la crittografia. E non si desidera utilizzare passphrase (intese per uso umano) per crittografarlo, una gestione delle chiavi piuttosto efficace, ad esempio protetta dal sistema operativo, in modo tale che l'accesso al file system non garantisca l'accesso alla chiave.
AviD,

3
La crittografia non è magica - invece di proteggere la chiave AES con ACL potresti semplicemente archiviare la password lì. Non vi è alcuna differenza tra l'accesso alla chiave AES o la password decrittografata, la crittografia in questo contesto è solo olio di serpente.
MarioVilas,

@MarioVilas whaat? Se la password è crittografata, con la chiave di crittografia protetta dal sistema operativo, in che modo non c'è differenza? La crittografia non è una magia: compatta solo tutta la segretezza nella chiave di crittografia più piccola. Difficilmente snakeoil, in questo contesto sta spostando tutta quella segretezza nel sistema operativo.
AviD,

6
@AviD come mai il sistema operativo può proteggere la chiave ma non i dati stessi? Risposta: può proteggere entrambi, quindi la crittografia non aiuta davvero. Sarebbe diverso se solo i dati fossero archiviati e la chiave di crittografia fosse derivata, ad esempio, da una password che doveva essere digitata da un utente.
MarioVilas,
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.