0

I've been reading through different secure ways to connect to databases and wanted to run this idea past you before I tie myself in knots trying it with my actual databases if it has no security benefits or simplification of switching between databases.

I was thinking that it would ensure the db_* variables are killed off after the function is used and the connection has been made to the relevant database:

<?php
function dbconn($db_hostname='localhost',
                $db_username='',
                $db_password='',
                $db_database='database1'
                $db_object='connection') {

    if($db_username=='' && $db_password=='') {
        switch ($db_database) {
            case 'database1':
                $db_username='user1'; 
                $db_password='pass1';
                break;
            case 'database2':
                $db_username='user2'; 
                $db_password='pass2';
                break;
            default: 
                echo "No database defined to connect to";
                break;
        }
    }
    else if($db_password=='') {
        switch ($db_username) {
        case 'root':
            $db_password='rootpass';
            break;
        case 'user':
            $db_password='userpass';
            break;
        default:
            echo "No password known for this user";
            break;
        }
    }

    $db_object= new mysqli($db_hostname, $db_username, $db_password, $db_database);
    if ($db_object->connect_error) die($db_object->connect_error);
} 
?>
Bendy
  • 3,506
  • 6
  • 40
  • 71
  • What are you trying to achieve with this, it's really not clear. Database usernames and passwords would normally be stored in a configuration file that is not accessible outside of the server. This means you can change the config without changing the code (e.g. when you move between environments or you change your password). Have only one place that accesses the config and builds the connection so you don't duplicate the grabbing. If you need more security than that then use a password manager library. – Rob Baillie Nov 11 '14 at 10:05
  • You should never be able to connect at all using this code, because you're always setting your variables to `''`. (`=` is assignment, `==` is comparison!) Beyond that I have no idea what you're asking or even what possible security problem you're trying to solve here. – deceze Nov 11 '14 at 10:09
  • Hmm, sorry if it's not clear then. I was trying to make the above the config file you mentioned Rob. This would be a directory above the website itself...and then `include('../functions.php');`. That way, I thought (apparently misguidedly!) I could then connect to any of my databases using `dbconn($db_database='database1');` or `dbconn($db_database='database2);` or even `dbconn($db_username='root', $db_database='database1');` ? – Bendy Nov 11 '14 at 10:21
  • 1. Well, yes, you *could* do that, if you fixed up your code (again: `=` vs. `==`). But I still fail to see what of your question is security related here. 2. You would never literally call `dbconn($db_username='root', $db_database='database1')`, that's not how function parameters work. If you literally attempt to use it that way, you need to go back to learning more about function parameters. – deceze Nov 11 '14 at 10:48
  • Herzlichen dank Deceze :) I updated the = vs == in my original question (I hope!). The reason why I tried putting it together is because I was worrying that having $db_password set and carrying my password string it would be susceptible to someone injecting code to `echo "$db_password"`...so I was thinking wrapping it in a function would kill the variable from memory after the function finished?...I agree I learn more on functions - I'm just starting out and it's daunting how many security risks there seems to be if you don't know exactly what you're doing :( – Bendy Nov 11 '14 at 11:05
  • Let's put it this way: if someone is able to **inject** "`echo $db_password;`" anywhere, you have already lost security-wise. Variable scope is the least of your worries in that case. – deceze Nov 11 '14 at 11:37

1 Answers1

1

It's unclear to me what you're trying to do, from the code you've provided. However, I can answer your question: "What is a secure way to connect to a database?"

With PHP working as a CGI-like language, the primary concern with connecting securely, is that your configuration file could be exposed. There are two possible solutions to this:

1. A PHP file as your configuration

This is probably the most common approach, and especially used often in redistributable software. By making your "configuration file" a PHP file that simply sets variables and is included in other pages, the PHP interpreter will parse this file, rather than returning its contents. The location of the file doesn't really matter - as long as it's somewhere where PHP files can be executed. In a typical application, this is anywhere in the document root except for the uploads directory.

An example configuration file (db_config.php):

<?php

$db_host = "localhost";
$db_user = "username";
$db_pass = "password";
$db_database = "database_name";

You would simply require('db_config.php'); in your initialization/header/etc. code.

You should only use the configuration file for configuring the connection, not for making it. This way, it makes it easy to change your connection code later on, without having to modify your configuration file on every server that your application runs on.

2. A serialized configuration file

Alternatively, you could use something like JSON or YAML to create a configuration file. The main advantage is that you can use the same configuration file for any auxiliary scripts or applications that need to connect to the same database, but aren't written in PHP.

However, you should never place this file in your document root. As far as your webserver is concerned, a JSON or YAML file is a 'viewable' file, and it will happily show it to anybody who has the URL.

The correct way to use a JSON/YAML/etc. file as your configuration file, is to make sure that it's placed outside of the document root, so that the webserver cannot possibly serve it up to a user. Trying to give it an 'unguessable' name is not sufficient.

You could also use something like .htaccess, but this is not recommended as it will make changing to other webservers harder, and a webserver misconfiguration could expose your database connection details. Only use this as an absolute last resort.

Other considerations

There are three other main points that I want to address here.

Multiple database credentials

In your original code, it looks like you're trying to add a feature where you can select the database you want to select to. In reality, this is almost never what you want. Every server/installation should only have its own database credentials.

If you follow the suggestions I gave for storing your configuration data, then it will be very easy to have a separate configuration file on each system, without having to ever change it. If you're using Git or another version control system that lets you ignore files, you can safely (and should) make it ignore the configuration file. You'll simply have a different configuration file on each server.

Overall security

Of course, you should make sure that your overall security is in proper working order. If you have a LFI vulnerability or somebody can upload a shell to your server, then no amount of putting files outside a document root is going to protect your database credentials. OWASP is a decent resource on general (web) application security.

PDO or mysqli_?

Judging from your snippet of code, you're using mysqli_. While this can be a valid choice if you use parameterization / prepared queries correctly, I would not recommend using it. PDO is a database-independent SQL library that focuses more heavily on parameterized queries. It's included by default in more or less every recent PHP installation, and as a bonus it'll let you switch between different SQL servers.

Using parameterized ("prepared") statements is absolutely critical - it is the only reliable way to prevent SQL injections, which seems to be the most important issue you'll want to protect yourself against here. A goood introductory guide can be found here.

Sven Slootweg
  • 3,735
  • 3
  • 21
  • 29
  • Hi Sven, thanks for such a thorough answer :) My code was an attempt to adapt a PHP file as a 'dynamic' configuration file...the reason being that I thought having the variables filled with the connection username and password that it would be susceptible to having them `echo "$db_password";` through injection hacks(!?)....I will also look into PDO - thanks very much :) – Bendy Nov 11 '14 at 10:45
  • @Bendy You may wish to have a look at http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php/60496#60496 – v010dya Nov 11 '14 at 10:47
  • @Volodya, thanks very much - I've just been reading through on PDO...sounds like a clear choice over sqli from what I've read. I will try moving over to PDO tonight...! – Bendy Nov 11 '14 at 11:34
  • 1
    @Bendy The only situation where it would be possible to output the database connection parameters, would be if you're using [variable variables](http://php.net/manual/en/language.variables.variable.php) and using user input to determine the variable name (which is really not something you should ever do - it's almost as dangerous as `eval`). If you're really concerned about this - eg. you have a coworker that may do this - you could use [unset](http://php.net/manual/en/function.unset.php) to (as the name implies) 'unset' the variables containing the database credentials after using them. – Sven Slootweg Nov 11 '14 at 13:04
  • Thanks Sven, I'm just a newbie hobbyist so have no colleagues code to worry about...just my own ;) ...and thanks to everyone else - I think I understand now and have been reading around PDO - I'm sold :) From what I understand, the `bindParam` functionality keeps the variable strings away from the database queries - so no risk of code injection. – Bendy Nov 11 '14 at 13:21
  • @Bendy Your understanding is correct :) It basically transmits the values separately from the query itself. – Sven Slootweg Nov 11 '14 at 18:23