Comment sécuriser les mots de passe de base de données en PHP?

404

Lorsqu'une application PHP établit une connexion à une base de données, elle doit bien entendu généralement transmettre un identifiant et un mot de passe. Si j'utilise une seule connexion avec des autorisations minimales pour mon application, alors le PHP doit connaître cette connexion et ce mot de passe quelque part. Quelle est la meilleure façon de sécuriser ce mot de passe? Il semble que l'écrire dans le code PHP ne soit pas une bonne idée.

user18359
la source
1
Pour être totalement sécurisé, vous devrez configurer une connexion SSL, sinon n'importe qui sur votre réseau pourra toujours renifler le mot de passe que vous tapez.
Charles Ma
1
Voulez-vous dire les mots de passe utilisateur ou le mot de passe de base de données utilisé dans la chaîne de connexion?
Ozgur Ozcitak
4
Mot de passe de la base de données utilisé dans la chaîne de connexion. Merci!
user18359

Réponses:

238

Plusieurs personnes ont mal interprété cela comme une question sur la façon de stocker les mots de passe dans une base de données. C'est faux. Il s'agit de savoir comment stocker le mot de passe qui vous permet d'accéder à la base de données.

La solution habituelle consiste à déplacer le mot de passe hors du code source dans un fichier de configuration. Laissez ensuite l'administration et la sécurisation de ce fichier de configuration à vos administrateurs système. De cette façon, les développeurs n'ont besoin de rien savoir sur les mots de passe de production, et il n'y a aucun enregistrement du mot de passe dans votre contrôle de source.

user11318
la source
8
Merci. Si je comprends bien, le fichier php aura alors une inclusion dans le fichier de configuration, lui permettant d'utiliser le mot de passe. par exemple, je crée un fichier appelé 'app1_db_cfg.php' qui stocke le nom de connexion, pword et db. Ensuite, ma page application.php comprend 'app1_db_cfg.php' et je suis en affaires!
user18359
28
Je suis d'accord que la config doit être correctement protégée. Cependant, savoir faire cela est l'affaire des administrateurs système, pas des développeurs. Je ne suis pas d'accord sur la valeur d'un cryptage fort dans ce cas. Si vous ne pouvez pas protéger votre fichier de configuration, qu'est-ce qui vous fait penser que vous pouvez protéger vos clés?
user11318
10
Je préfère utiliser un compte de base de données qui n'est autorisé à accéder à la base de données qu'à partir du serveur Web. Et puis je ne me soucie pas de crypter la configuration, je la stocke juste en dehors de la racine Web.
gnud
11
J'utilise une variable d'environnement apache pour définir le chemin afin que même le chemin vers le fichier soit inconnu dans le code source. Cela permet également d'avoir un mot de passe différent pour le développement et la production en fonction des paramètres Apache sur le serveur
geedew
15
N'oubliez pas que même les fichiers stockés en dehors du répertoire accessible sur le Web doivent être lus par le script qui les utilise. Si quelqu'un inclut ce fichier, puis vide les données du fichier, il verra le mot de passe.
Rick Mac Gillis
104

Si vous hébergez sur le serveur de quelqu'un d'autre et que vous n'avez pas accès en dehors de votre racine Web, vous pouvez toujours mettre votre mot de passe et / ou votre connexion à la base de données dans un fichier, puis verrouiller le fichier à l'aide d'un .htaccess:

<files mypasswdfile>
order allow,deny
deny from all
</files>
kellen
la source
3
Merci, c'est exactement ce que je cherchais.
David Gladfelter
28
Certainement, mais si quelqu'un a accès au shell, votre compte entier a quand même été compromis.
kellen
4
Il s'agit d'une mauvaise pratique car vous pouvez accidentellement valider vos informations d'identification dans un référentiel.
Porlune
2
@Ankit: S'il est possible pour un non-ami de télécharger un fichier sur le serveur et de l'exécuter, alors le serveur n'est pas correctement configuré.
kellen
6
@Porlune: Les développeurs doivent faire en sorte que leur système de contrôle de version ignore le fichier de mot de passe, c'est-à-dire en utilisant un .gitignore. Mais oui, il faut faire attention aux fichiers qui contiennent des données sensibles.
kellen
45

Le moyen le plus sûr est de ne pas avoir du tout les informations spécifiées dans votre code PHP.

Si vous utilisez Apache, cela signifie définir les détails de connexion dans votre fichier de fichier httpd.conf ou virtual hosts. Si vous faites cela, vous pouvez appeler mysql_connect () sans paramètres, ce qui signifie que PHP ne sortira jamais vos informations.

Voici comment vous spécifiez ces valeurs dans ces fichiers:

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

Ensuite, vous ouvrez votre connexion mysql comme ceci:

<?php
$db = mysqli_connect();

Ou comme ça:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));
Lars Nyström
la source
1
Veuillez vérifier les valeurs appropriées de ini_get ('valeurs par défaut') php.net/manual/en/class.mysqli.php
Val
4
oui, mais tout utilisateur (ou un pirate abusant d'un script php mal écrit) peut lire le mot de passe via ini_get().
Marki555
1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()Comment gérez -vous cela?
tonix
2
Marki555 dit qu'un attaquant qui peut exécuter du code PHP peut également appeler des fonctions PHP, ce qui est évidemment vrai et impossible à faire. Je voudrais également ajouter que je ne suis plus moi-même le conseil que je donne dans cette réponse, mais que j'utilise plutôt des variables d'environnement. Le concept est similaire cependant: ne stockez pas vos informations d'identification dans le code, mais injectez-les d'une manière ou d'une autre. Peu importe que vous utilisiez ini_get()ou getenv().
Lars Nyström
2
@DeepBlue Si vous pouvez injecter ini_get (), vous pouvez également injecter file_get_contents (anypath). Tant que php a un moyen d'accéder au mot de passe, il en sera de même pour tout code malveillant.
varesa
40

Stockez-les dans un fichier en dehors de la racine Web.

da5id
la source
29
Et aussi, comme mentionné ailleurs, en dehors du contrôle des sources.
Frank Farmer
6
nous pourrions l'inclure? par exemple, en PHP, pouvons-nous faire alors include('../otherDirectory/configfile.conf')?
mtk
1
Vous proposez tous de stocker les informations d'identification en dehors de wwwroot. Ok, je comprends le contexte de la sécurité. Mais comment le stocker dans le contrôle de version (exemple de configuration)? Habituellement, wwwroot est la racine de git repo, donc s'il y a quelque chose à l'extérieur - ce sera à l'extérieur de VC. Imaginez un nouveau développeur essayant de mettre en place une instance locale pour le développement - comment devrait-il connaître la magie comme "prendre ce fichier, le copier à l'extérieur et le remplir"?
The Godfather
@TheGodfather L'idée est qu'un nouveau développeur devrait avoir ses propres informations d'identification pour son propre environnement de développement. Bien que ce soit une bonne pratique d'avoir un fichier Lisez-moi avec des instructions ou des commentaires dans le code indiquant comment vous devez le configurer (mais pas les données réelles).
PhoneixS
@TheGodfather, fichier Lisez-moi?
Pacerier
35

Pour les systèmes extrêmement sécurisés, nous chiffrons le mot de passe de la base de données dans un fichier de configuration (lui-même sécurisé par l'administrateur système). Au démarrage de l'application / du serveur, l'application invite ensuite l'administrateur système à saisir la clé de déchiffrement. Le mot de passe de la base de données est ensuite lu dans le fichier de configuration, déchiffré et stocké en mémoire pour une utilisation future. Toujours pas sûr à 100% car il est stocké dans la mémoire déchiffrée, mais vous devez l'appeler `` suffisamment sécurisé '' à un moment donné!

pdavis
la source
85
que faire si l'administrateur décède?
Radu Murzea
36
@RaduMurzea c'est ridicule. Quand avez-vous entendu parler de la mort des administrateurs système? Ils sont comme McDonalds, ils apparaissent / disparaissent de nulle part!
ILikeTacos
13
@Radu Murzea Il suffit d'avoir 2 administrateurs ou plus, alors vous avez la parité comme un tableau de raid. Les chances que plusieurs disques tombent en panne à la fois sont beaucoup plus faibles.
element11
5
qu'en est-il lorsque les serveurs redémarrent? Qu'en est-il du temps qu'il faut pour réveiller l'administrateur pour qu'il saisisse le mot de passe dans..etc.etc. lol
John Hunt
1
Je ne sais pas ce que vous entendez par «stocké en mémoire». Les applications Web PHP ne stockent généralement rien en mémoire plus longtemps que le temps nécessaire pour répondre à une demande individuelle de voir une page.
bdsl
15

Cette solution est générale, en ce sens qu'elle est utile pour les applications open source et fermées.

  1. Créez un utilisateur du système d'exploitation pour votre application. Voir http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Créer une variable d'environnement de système d'exploitation (hors session) pour cet utilisateur, avec le mot de passe
  3. Exécutez l'application en tant qu'utilisateur

Avantages:

  1. Vous ne vérifierez pas vos mots de passe dans le contrôle de code source par accident, car vous ne pouvez pas
  2. Vous ne ferez pas accidentellement des permissions sur les fichiers. Eh bien, vous pourriez, mais cela n'affectera pas cela.
  3. Ne peut être lu que par root ou par cet utilisateur. Root peut lire tous vos fichiers et clés de cryptage de toute façon.
  4. Si vous utilisez le cryptage, comment stockez-vous la clé en toute sécurité?
  5. Works x-platform
  6. Assurez-vous de ne pas transmettre l'envvar à des processus enfants non approuvés

Cette méthode est suggérée par Heroku, qui a beaucoup de succès.

Neil McGuigan
la source
11

s'il est possible de créer la connexion à la base de données dans le même fichier où les informations d'identification sont stockées. Insérez les informations d'identification dans l'instruction connect.

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

Sinon, il est préférable de désactiver les informations d'identification après l'instruction connect, car les informations d'identification qui ne sont pas en mémoire ne peuvent pas être lues depuis la mémoire ;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  
Bob Fanger
la source
9
Si quelqu'un a accès à la mémoire, vous êtes quand même foutu. C'est une fausse sécurité inutile. En dehors du webroot (ou au moins protégé par un .htaccess si vous n'avez pas accès au-dessus de votre webroot) est la seule option sûre.
uliwitness
2
@uliwitness - C'est comme dire que le simple fait que quelqu'un puisse percer la serrure de votre centre d'exploitation de réseau avec une torche à acétylène signifie que la porte est également une fausse sécurité. Garder les informations sensibles liées à la portée la plus étroite possible est toujours logique.
Luke A. Leber
1
Que diriez-vous d'écho $ db_user ou d'imprimer le $ db_pass? Même les développeurs de la même équipe ne devraient pas être en mesure de déterminer les informations d'identification de production. Le code ne doit contenir aucun élément imprimable sur les informations de connexion.
Mohammed Joraid
8

Vos choix sont plutôt limités car vous dites que vous avez besoin du mot de passe pour accéder à la base de données. Une approche générale consiste à stocker le nom d'utilisateur et le mot de passe dans un fichier de configuration séparé plutôt que dans le script principal. Veillez ensuite à le stocker en dehors de l'arborescence Web principale. En cas de problème de configuration Web qui laisse vos fichiers php affichés simplement sous forme de texte plutôt que d'être exécutés, vous n'avez pas exposé le mot de passe.

En dehors de cela, vous êtes sur la bonne voie avec un accès minimal au compte utilisé. Ajouté à cela

  • N'utilisez pas la combinaison nom d'utilisateur / mot de passe pour autre chose
  • Configurez le serveur de base de données pour accepter uniquement les connexions de l'hôte Web pour cet utilisateur (l'hôte local est encore meilleur si la base de données est sur la même machine). De cette façon, même si les informations d'identification sont exposées, elles ne sont utiles à personne, sauf si elles ont un autre accès au machine.
  • Obscurcir le mot de passe (même ROT13 fera l'affaire), il ne mettra pas beaucoup de défense si certains ont accès au fichier, mais au moins il empêchera sa visualisation occasionnelle.

Peter

Vagnerr
la source
8

Si vous utilisez PostgreSQL, il recherche ~/.pgpassautomatiquement les mots de passe. Voir le manuel pour plus d'informations.

Jim
la source
8

Auparavant, nous stockions l'utilisateur DB / pass dans un fichier de configuration, mais avons depuis frappé le mode paranoïaque - en adoptant une politique de défense en profondeur .

Si votre application est compromise, l'utilisateur aura un accès en lecture à votre fichier de configuration et il est donc possible qu'un pirate puisse lire ces informations. Les fichiers de configuration peuvent également être pris dans le contrôle de version ou copiés sur les serveurs.

Nous sommes passés au stockage des variables d'environnement user / pass dans l'ensemble Apache VirtualHost. Cette configuration n'est lisible que par root - espérons que votre utilisateur Apache ne s'exécute pas en tant que root.

L'inconvénient est que maintenant le mot de passe est dans une variable PHP globale.

Pour atténuer ce risque, nous avons les précautions suivantes:

  • Le mot de passe est crypté. Nous étendons la classe PDO pour inclure la logique de décryptage du mot de passe. Si quelqu'un lit le code où nous établissons une connexion, il ne sera pas évident que la connexion est établie avec un mot de passe crypté et non le mot de passe lui-même.
  • Le mot de passe chiffré est déplacé des variables globales vers une variable privée. L'application le fait immédiatement pour réduire la fenêtre de disponibilité de la valeur dans l'espace global.
  • phpinfo()est désactivé. PHPInfo est une cible facile pour obtenir un aperçu de tout, y compris des variables d'environnement.
Courtney Miles
la source
6

Mettez le mot de passe de la base de données dans un fichier, rendez-le en lecture seule pour l'utilisateur qui sert les fichiers.

Sauf si vous avez un moyen d'autoriser uniquement le processus du serveur php à accéder à la base de données, c'est à peu près tout ce que vous pouvez faire.

Chris
la source
5

Si vous parlez du mot de passe de la base de données, par opposition au mot de passe provenant d'un navigateur, la pratique standard semble être de mettre le mot de passe de la base de données dans un fichier de configuration PHP sur le serveur.

Il vous suffit de vous assurer que le fichier php contenant le mot de passe dispose des autorisations appropriées. C'est-à-dire qu'il ne doit être lisible que par le serveur Web et par votre compte d'utilisateur.

Jason Wadsworth
la source
1
Malheureusement, le fichier de configuration PHP peut être lu par phpinfo () et si quelqu'un laisse un script de test derrière lui, un attaquant chanceux pourra lire le mot de passe. Il est probablement préférable de laisser le mot de passe de connexion dans un fichier en dehors de la racine du serveur Web. Ensuite, le seul moyen d'y accéder est soit avec un shell, soit en exécutant du code arbitraire, mais dans ce scénario, toute sécurité est de toute façon perdue.
MarioVilas
5

Le mettre dans un fichier de configuration quelque part est la façon dont cela se fait habituellement. Assurez-vous simplement:

  1. interdire l'accès à la base de données à partir de tout serveur extérieur à votre réseau,
  2. veillez à ne pas montrer accidentellement le mot de passe aux utilisateurs (dans un message d'erreur, ou à travers des fichiers PHP accidentellement servis en HTML, etc.)
Marijn
la source
5

Nous l'avons résolu de cette façon:

  1. Utilisez memcache sur le serveur, avec une connexion ouverte à partir d'un autre serveur de mots de passe.
  2. Enregistrez dans memcache le mot de passe (ou même tout le fichier password.php chiffré) plus la clé de déchiffrement.
  3. Le site Web appelle la clé memcache contenant la phrase secrète du fichier de mots de passe et déchiffre en mémoire tous les mots de passe.
  4. Le serveur de mots de passe envoie un nouveau fichier de mot de passe crypté toutes les 5 minutes.
  5. Si vous utilisez un mot de passe crypté.php sur votre projet, vous mettez un audit, qui vérifie si ce fichier a été touché en externe - ou visualisé. Lorsque cela se produit, vous pouvez automatiquement nettoyer la mémoire et fermer le serveur pour y accéder.
Asi Azulay
la source
4

Une astuce supplémentaire consiste à utiliser un fichier de configuration PHP séparé qui ressemble à ceci:

<?php exit() ?>

[...]

Plain text data including password

Cela ne vous empêche pas de définir correctement les règles d'accès. Mais dans le cas où votre site Web est piraté, un "require" ou un "include" quittera simplement le script à la première ligne, il est donc encore plus difficile d'obtenir les données.

Néanmoins, ne laissez jamais les fichiers de configuration dans un répertoire accessible via le Web. Vous devriez avoir un dossier "Web" contenant votre code de contrôleur, css, images et js. C'est tout. Tout le reste va dans des dossiers hors ligne.

e-satis
la source
mais alors comment le script php lit-il les informations d'identification stockées dans le fichier?
Christopher Mahan
3
Vous utilisez fopen (), comme pour un fichier texte normal.
e-satis
2
@ e-satis ok ça va empêcher les hackers de faire require/ includemais comment éviter de faire fopen?
dmnc
"cela ne vous empêche pas de définir correctement les règles d'accès"
e-satis
@ e-satis, c'est assez intelligent. me demande pourquoi personne n'y avait pensé. Cependant , toujours vulnérable au problème de copie de l'éditeur. feross.org/cmsploit
Pacerier
4

Le meilleur moyen est de ne pas stocker du tout le mot de passe!
Par exemple, si vous utilisez un système Windows et que vous vous connectez à SQL Server, vous pouvez utiliser l'authentification intégrée pour vous connecter à la base de données sans mot de passe, en utilisant l'identité du processus en cours.

Si vous devez vous connecter avec un mot de passe, commencez par le chiffrer , en utilisant un chiffrement fort (par exemple en utilisant AES-256, puis en protégeant la clé de chiffrement, ou en utilisant un chiffrement asymétrique et que le système d'exploitation protège le certificat), puis stockez-le dans un fichier de configuration (en dehors du répertoire Web) avec des ACL solides .

Avide
la source
3
Inutile de crypter à nouveau le mot de passe . Quelqu'un qui pourrait obtenir le mot de passe non chiffré peut également obtenir la phrase secrète nécessaire pour déchiffrer le mot de passe. Cependant, l'utilisation des listes de contrôle d'accès et .htaccess est une bonne idée.
uliwitness
2
@uliwitness Je pense que vous avez peut-être mal compris - que voulez-vous dire par "crypter à nouveau "? C'est juste le seul cryptage. Et vous ne voulez pas utiliser de mots de passe (destinés à un usage humain) pour le chiffrer, une gestion des clés plutôt solide, par exemple protégée par le système d'exploitation, de telle manière que le simple accès au système de fichiers n'accordera pas l'accès à la clé.
AviD
3
Le chiffrement n'est pas magique - au lieu de protéger la clé AES avec des ACL, vous pouvez simplement y stocker le mot de passe. Il n'y a pas de différence entre accéder à la clé AES ou au mot de passe décrypté, le cryptage dans ce contexte n'est que de l'huile de serpent.
MarioVilas
@MarioVilas whaat? Si le mot de passe est crypté, avec la clé de cryptage protégée par le système d'exploitation, comment n'y a-t-il aucune différence? Le chiffrement n'est pas magique - il compacte tout le secret dans la plus petite clé de chiffrement. À peine snakeoil, dans ce contexte, il ne fait que déplacer tout ce secret dans le système d'exploitation.
AviD
6
@AviD comment se fait-il que le système d'exploitation puisse protéger la clé mais pas les données elles-mêmes? Réponse: il peut protéger les deux, donc le cryptage n'aide pas vraiment. Ce serait différent si seules les données étaient stockées et que la clé de cryptage était dérivée, par exemple, d'un mot de passe qui devait être tapé par un utilisateur.
MarioVilas