The problem with DEFINE (in PHP) - The WWW

Users browsing this thread: 1 Guest(s)
eksith
Long time nixers
Anyone who's played for even a little bit in PHP has come across this problem one time or another: Where to store the keys to your precious castle. Whether that's your database connection settings, some passwords or other secret salts, it's still a bit of a concern since it only takes one misconfiguration to allow your server to send PHP as plaintext to the visitor and (*gasp*) there go your credentials with it. This happens quite a lot, unfortunately.

The solution to this is fairly simple, if you have access to php.ini. If you run your own box (highly recommended) you already have access to this, but most new web hosts do allow it as well. If not, it may be time to switch. The tricky bit still is grabbing all those settings.

Somewhere toward the bottom of your php.ini, you can add something similar to:
Code:
[MyCustomApp]
myapp.cfg.DB_HOST = 'mysql:host=127.0.0.1;dbname=mydatabase'
myapp.cfg.DB_USER = 'dbusername'
myapp.cfg.DB_PASS = 'dbpassword'

MyCustomApp is just a label for that group of settings (this is generally good practice). And myapp.cfg. is just the prefix to your collection of custom settings.

And now in the rest of your code, you can use a simple function and an array with the list of variables you want defined.
Code:
function loadConfig( $vars = array() ) {
    foreach( $vars as $v ) {
        define( $v, get_cfg_var( "myapp.cfg.$v" ) );
    }
}

// Then call :
$cfg = array( 'DB_HOST', 'DB_USER', 'DB_PASS' );
loadConfig( $cfg );

And viola! You don't have to store the crown jewels in the most easily accessible portion of your script. The above code is the safer equivalent of :
Code:
define( 'DB_HOST', 'mysql:host=127.0.0.1;dbname=mydatabase' );
define( 'DB_USER', 'dbusername' );
define( 'DB_PASS', 'dbpassword' );
... which is the old and more vulnerable way.

There's an even more paranoid version of this possible if you host more than one site: Put one secret key in your php.ini and put another in your script. Hash the two together and you get a combined key that can be used to decrypt a separate settings file courtesy of our friend, parse_ini_string. It basically grabs all the settings in ini format (this is why it's good practice to give your settings lables) and puts it into an easily digestable array.

That's a bit more complicated, but doable. In php.ini :
Code:
sites.cfg.commonkey = 'your super secret key'

And in your script :
Code:
define( 'SCRIPT_KEY',    'Another secret key' );
define( 'INI_PATH',    '/path/to/encrypted-settings.txt' );

function loadCfg() {
    $sharedKey    = get_cfg_var( 'sites.cfg.commonkey' );
    
    $hash        = hash( 'tiger160,4', $sharedKey . SCRIPT_KEY );
    
    $file        = fopen( INI_PATH, 'r' );
    $ini        = fread( $file, filesize( INI_PATH );
    fclose( $file );
    
    $ini        = decrypt( $ini, $hash );
    
    // And get all your settings into a nicely bundled array
    $settings    = parse_ini_string( $ini );
}

Naturally, you'll need to encrypt the file first so instead of 'decrypt', you'll just use an 'encrypt' function (probably during the initial setup of your site) and paste the garbled stuff in the text file.

There are plenty of examples out there on PHP encryption, but if you feel like it, you can use a library I wrote that has additional features like password generation/hashing, IVs etc...

Any bugs, questions, better ways? Please reply.

Enjoy! :)


Messages In This Thread
The problem with DEFINE (in PHP) - by eksith - 16-10-2013, 09:31 AM
RE: The problem with DEFINE (in PHP) - by eksith - 16-10-2013, 11:04 AM
RE: The problem with DEFINE (in PHP) - by venam - 16-10-2013, 11:28 AM
RE: The problem with DEFINE (in PHP) - by eksith - 16-10-2013, 02:55 PM
RE: The problem with DEFINE (in PHP) - by eksith - 16-10-2013, 04:08 PM
RE: The problem with DEFINE (in PHP) - by desyncr - 21-11-2013, 08:23 PM