Is it safe to store password in php file?

5 hours ago, monollonom said:

It's a very interesting setup @FireWire but I was wondering how you're dealing with API keys when used by modules. Usually, like in your (excellent) Fluency module, API keys are stored in the db through the module configuration, which is convenient since it's local to the module but in your setup ends up scattering around your credentials.

It's an open question but should there be a $config object that would contain api keys that modules could check first and if empty rely on the administrator to input these in the module configuration ?

You're 100% right about the DB storage of keys for modules. My use case for the credentials in .env is for non-module related needs that are necessary in various scripts around the codebase. Some of which aren't in the ProcessWire namespace so wire() & $config aren't available.

A good example is where I work I've built a company-wide REST API to interact with our systems so those keys are in .env. It makes it very easy to work with at a glance. With clean variable names I haven't run into any $_ENV pollution/collisions. Two custom variables that we do create are $config->envIsProduction and $config->envIsDevelopment to help alter code behavior when needed, we use that to do things like switch scripts in markup (like production/development Google Tag Manager/Analytics).

Here's a more robust (dummy) example of our local development .env,

ENVIRONMENT="development" # Either production or development

# CMS
CMS_DEBUG="true"
CMS_CHMOD_DIR=0755
CMS_CHMOD_FILE=0644
CMS_USE_PAGE_CLASSES="true"
CMS_USE_FUNCTIONS_API="true"
CMS_PREPEND_TEMPLATE_FILE="_init.php"
CMS_USER_AUTH_SALT="d5e3ac4deba1e382255bbd8755d7e713"
CMS_LOCALE="en_US.UTF-8"
CMS_TIMEZONE="America/Los_Angeles"
CMS_DEFAULT_ADMIN_THEME="AdminThemeUikit"
CMS_INSTALLED=1580677417
CMS_MODULE_INSTALL="true"

# CMS Database - Development
CMS_DB_HOST="127.0.0.1"
CMS_DB_NAME="pw_website_db_name"
CMS_DB_USER="db_user_name"
CMS_DB_PASS="hB99kVrqS444VZlrrr"
CMS_DB_PORT="3306"
CMS_DB_ENGINE="InnoDB"

# Renova Energy API - Development
RE_API_URL="https://secure-tunnel-url.ngrok.io/"
RE_API_KEY_WEBSITE="d5d891e204f5473990bb533cf7fca22f"
RE_API_KEY_EVENT="531706b9837744ecbbf2b008bc11a681"

# Mailgun
MG_KEY="5af07ec6-315c-48d9-b615-f1cfb3d75820"
MG_DOMAIN="mg.ourconfigureddomain.com"

# Forecast.io
FORECAST_IO_KEY="5fce4a3251f711ecbf630242ac130002"

# CallTrackingMetrics Webhook Auth Token
CTM_WEBHOOK_AUTH_HASH="227040707a1b4e13bc88facf928defe0"

# Web API Authentication Keys
WEB_API_KEY_SALESFORCE="84f13985-77f5-4521-9c2d-1567ddb9bf2e"
WEB_API_KEY_APP="e7051f6e-5905-47f6-9108-93d2f02a53b8"

Also, thank you for the kind words about Fluency, looking forward to the next big (biggest yet) release soon!

WHERE TO STORE ACCESS DATA

You probably know that is not a good idea to keep access data unencrypted.

Account passwords, for example, should never be stored in plain text on the database (here is exactly how to hash passwords with php).

In some cases, however, access information needs to be unencrypted.

When PHP connects to a database, for example, it needs to provide plain text username and password to the database extension (PDO, MySQLi etc.).

Such access data cannot be encrypted, otherwise it would be inaccessible to PHP.

Where should you store plain text access data like that?

A good solution (the one I use too) is to keep it inside a separate PHP script. In the case of database connection data, this separate script should also connect to the database and then unset the access data variables in order to minimize the risk of data leaks.

This is how this file looks like:

<?php

$db = array();
$db['host'] = 'localhost';
$db['schema'] = 'db_schema';
$db['username'] = 'db_user';
$db['password'] = 'db_passwd';

$PDO = NULL;

try
{
	$PDO = new PDO('mysql:host=' .  $db['host'] . ';dbname=' .  $db['schema'], $db['username'],  $db['password']);
	$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	$PDO->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
}
catch (PDOException $e)
{
	echo 'Connection failed.';
	die();
}

/* We don't need access data any more here */
unset($db);

This file will be included by every PHP script that needs to access the database. The PDO object will be available and ready to be used (you can use any other database extension, of course) but the database access data will not be available any more.

For more details about how to connect to MySQL with PHP see my complete tutorial:

  • How to use PHP with MySQL: the complete tutorial

A great security improvement is to keep the access PHP file outside of the web server root directory, so that it cannot be accessed by remote clients.

It’s true that the web server doesn’t show the PHP code to remote clients, but since PHP can include files from any where (as long as the file is readable by the user running PHP) there is no reason to let remote users access this file. 

Prevention is a very important part of a security framework.

What If there is some issue with the web server configuration? What if a security flaw can be used to read the PHP scripts’ content?

By storing the access script outside of the web server root, you will minimize the chances that it can be read by a malicious user.

Unfortunately you cannot keep it completely unreadable from the web server, because the PHP system user is the same as the web server’s.

However, you can make the file access policy as strict as possible and make it readable from the PHP user only.

If you use a *nix like system like Linux, you can use the chmod command to prevent other system users to read it.

Are passwords safe in PHP?

PHP provides a native password hashing API that safely handles both hashing and verifying passwords in a secure manner. Another option is the crypt() function, which supports several hashing algorithms.

Which is the safest way to store a password?

There is no better way to keep your passwords safe than to use a password manager, like Bitwarden. A good password manager should do more than store passwords, such as generate strong passwords and monitor data breaches for compromised passwords.

How secure is username and password in PHP?

Getting Started. There are a few steps we need to take before we create our secure login system. ... .
Creating the Login Form Design. ... .
Creating the Database and setting-up Tables. ... .
Authenticating Users with PHP. ... .
Creating the Home Page. ... .
Creating the Profile Page. ... .
Creating the Logout Script..

How can I protect my database password in PHP?

password_hash() function provides the facility to securely store the password of the user to the database. Example: First parameter Password will contain the normal password. The second Parameter will contain PASSWORD_BCRYPT to make secure otherwise it contains PASSWORD_DEFAULT as default.