In a PHP application I am writing, I would like not to expose the production DB credentials to other developers.
I read several questions and answers here on SO, e.g. the following thread has many interesting thoughts regarding the topic:
How to secure database passwords in PHP?
I decided that I want to move the credentials in a file outside the application's root. Suppose that I am using PDO and that within my application container I create my PDO instance:
<?php
// ...
require_once __DIR__ . '/../db_pdo_outside_document_root.php';
$containerConfig = [
'db_connection' => function() {
return new PDO(DB_PDO_DSN, DB_PDO_USER, DB_PDO_PASSWD, DB_PDO_OPTIONS);
}
];
$appContainer = new ApplicationContainer($containerConfig);
// Use the container and handle the request...
The DB_PDO_*
constants passed to the PDO constructor all come from the file db_pdo_outside_document_root.php
which is outside the document root:
<?php
// db_pdo_outside_document_root.php
define('DB_PDO_DSN', 'mysql:host=localhost;dbname=app_database');
define('DB_PDO_USER', 'db_user');
define('DB_PDO_PASSWD', 'db_fancy_passwd');
define('DB_PDO_OPTIONS', [
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
So far, so good. However, this doesn't help much, because if someone wants to echo the contents of the constants, they can easily do it:
<?php
// In some PHP file used by the application...
echo DB_PDO_PASSWD; // echoes the DB password.
//mail('developer@mail.com', 'Subject', DB_PDO_PASSWD); // Or send it by email
Now, of course, you must trust the colleagues you work with, but who knows, sometimes it happens that an employee leaves, maybe it is fired, and so on. And we don't want them to have a chance to somehow store production DB credentials on their computers.
So I thought that maybe, instead of defining the constants within the file, the file itself can return the PDO object, which in turn seems not to expose the credentials it uses to connect to the database:
<?php
// ...
var_dump($appContainer->get('db_connection'))
Outputs something like:
/path/to/htdocs/file.php:4:
object(PDO)[13]
So I would end up with something like this within my application's bootstrap code:
<?php
// ...
$containerConfig = [
'db_connection' => function() {
return require_once __DIR__ . '/../db_pdo_outside_document_root.php';
}
];
$appContainer = new ApplicationContainer($containerConfig);
// Use the container and handle the request...
And inside the outer file:
<?php
// db_pdo_outside_document_root.php
return new PDO('mysql:host=localhost;dbname=app_database',
'db_user', 'db_fancy_passwd', [
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);;
But I don't know if this is enough or if there are some caveats I should be aware of (apart from the fact that this "workaround" is a bit ugly).
Do you think other developers will be able to somehow read the credentials from the return value of $appContainer->get('db_connection')
(supposing that it returns the PDO object above)?
I also tried with ReflectionClass
and I do not see any property on that object:
<?php
//...
$ref = new ReflectionClass($appContainer->get('db_connection'));
var_dump($ref->getProperties());
Outputs:
/path/to/htdocs/file.php:4:
array (size=0)
empty
What do you think about this approach? Not the invention of the century but it seems that it does the job. Or, maybe there is still a way to access the credentials in the application's code I am not aware of.
I would like to have your opinions.
Thank you for the attention.
EDI: as @IsThisJavascript pointed out, application's code of course can still get the contents of the file and therefore access the credentials, therefore my whole reasoning was not correct as it didn't consider this very simple case. Guess I have to find another strategy, if one exists...