Best practice securing SQL Database Credentials with PHP - php

I currently have a web pages which pull data from an SQL database and display it using php to handle the connection and query.
I am currently using this snippet in my PHP file to connect and pull data:
$conn = odbc_connect(
"DRIVER={SQL Server Native Client 10.0};Server=xxx.xxx.xxx.xxx;Database=databasename", "username", "password");
if (!($conn)) {
echo "<p>Connection to DB via ODBC failed: ";
echo odbc_errormsg ($conn );
echo "</p>\n";
}
Does anyone see vulnerability with this and is there practice I should use?

I would put code such as this into a PHP Class file, and model it after the DAO Pattern (Data Access Object). Then, use the require or require_once directive on the script(s) that need to read/write to the DB.
This cuts down on the repetition and adheres to D.R.Y (Don't repeat yourself), when other scripts/code needs to read/write to the same DB, you'll already have a method in place to do so.
I would recommend against printing the error message to the screen. By all means, log it to a file (or check the error logs to see what happened).

As Adam T suggests, this type of code should definitely be captured in a separate file that is re-usable across your application (perhaps this is already the case - not clear from the details given).
If you look at any CMS system eg. WordPress, Joomla or Drupal, you will see they all store the DB credentials in plain text in a config.php file or similar, that gets read in early in the request processing cycle.
With respect to vulnerabilities though, ultimately, you have to place the login credentials somewhere that the PHP code can access it, so either it has to be stored in clear text in a PHP or text file that gets included or read in, or else obfuscated in some way, though generally this is a waste of time and effort.
Your best bet is to ensure the file containing the login credentials is suitably protected via filesystem permissions to prevent access from unauthorised prying eyes.

Related

Secure DB connection function?

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);
}
?>
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.

How to avoid including database connection file in every page?

Suppose i have a page config.php which contains
<?php
$username = "your_name";
$password = "your_password";
$hostname = "localhost";
//connection to the database
$dbhandle = mysql_connect($hostname, $username, $password)
or die("Unable to connect to MySQL");
echo "Connected to MySQL<br>";
?>
I know i need to include this config.php file where i want to ensure database connection.But is there any way to do this globally so that i don't need to include connection file in every required page ?I am asking so because i have seen lots of script where they are running query in a particular php page without including the database connection file!
My usual approach is to create an autoloader function to pull in classes as I need them and have a class handle the DB connection. However that might be a bit excessive for some projects. Also that config still needs to be included prior to my code that calls for a class and expects something to go and get it.
A lot of open source PHP software will set values like this in a config file which gets included very early on along with any libraries etc.
For Example (LM)NucleusCMS uses the config file to load the global functions and other core classes and that way the only thing a PHP script needs to do is ensure that config.php has been included.
Sometimes code you are looking at is intended to be included at run time by other code and so trusts that these settings are already in place. For example I am currently working on a project that redirects all calls to PHP files to start.php which does what is needed and then calls for the file after that and then finally calls for the template to process the output.
If you really want to do no includes at all then there is one other option but it is not recommended. You could set the php.ini directive auto_prepend_file and have the file included in EVERY script the server runs. As I said, you probably do not want this.
However that said if you would like to have the script handle the including for you and this is important then using the .htaccess and start.php example (actually ./engine/start.php) then this might work for you better than fooling about with ini directives. However the downside is that you need to check that your .htaccess redirects are working properly passing the filename back to the start.php and then make sure that some naughty user is not asking your script to do something bad. Once you have sanitised and sanity checked the input then you can go ahead and require_once($filename)...
My .htaccess looks a bit like this:
RewriteEngine on
RewriteRule ^(.*).php?$ ./path/to/start.php?page=$1 [QSA,L]
However, as I have said unless you have a specific need to do this then it would be safer not to as you are allowing ANY input into the include/require line and have to spend a lot of resources on EVERY page load making sure the request is safe.
To be honest the most common best practice is to have a file called, say common.php, and have all of the includes that the scripts need to get to in there and just
require_once('./path/to/common.php');
at the top of every page. If your project ends up with a lot of classes and/or libraries in it then you might be glad that you did.
The way I normally handle my Database connections is to include my config file in my header.php (which handles the navigation, logo, etc) file and the header file has to be included everywhere to keep uniformity.
So that is one solution that you can try
You should include this code on every page. That's how PHP works.
If you don't want to do it manually and your project is quite big you should probably consider using a framework on your project. Good PHP framework can take care of DB connection and many other common tasks such as request/response processing, validation etc.
There are plenty of PHP frameworks and you can select what will fit you.

Set up PDO connection without password

I'm trying to connect to my database, but I changed my database's root password in the interest of security. However, in order to connect to the database and use PDO, I apparently have to pass my password in the php, which obviously is not good for security:
$hsdbc = new PDO('mysql:dbname=hs database;host=127.0.0.1;charset=utf8', 'root','passwordgoeshere');
$hsdbc->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$hsdbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Am I being stupid and that because it's PHP no-one but the person who views the actual file will be able to see the password, or is there some way to do it without passing the password in the file.
Generally speaking it's not bad practice to have connection strings in files that are not user facing. If you don't want to have your personal password in the php file, then you can create a new mysql user for php.
You can also restrict the user's IP address in MySQL to the server hosting your php scripts. This way if a nefarious person browsing the web somehow was able to see the database password, they would have more difficulty accessing it.
People are not able to just go and read into your files. They should be safe on the place where you host it. They are only able to get into to files if they are able to get into the place when you host your stuff. Which should not be possible if they don't have the info to get there.(which should only be known to you).
This is not just for PDO. but also my mysql and mysqli to do it like this
Going to extend SupSon (SC2 Select fan?)'s answer:
PHP itself is server coded language.
There are only 3 ways (maybe more if someone want to add to it) that code can be shown to an outside user:
By having an unsecure .htaccess file that shows php file as text
file (then you should move servers at that point because normally
this doesn't happen)
Somehow your operating on debug mode and something in your page
triggers this mode and you get a whole bunch of PHP code gets shown
FTP/SSH access to your .php file (then you have more than a PDO
problem in your hands)
So if one of these cases is happening, coding into a .php file your username/password won't be a breach in security.
I have seen websites that expose PHP code, when the Apache type handler for PHP becomes unconfigured by accident. Then the code in .php files is displayed instead of executed. There's also an Apache type handler to display PHP source deliberately, though this is not usually configured.
To avoid this vulnerability, it's a good practice to put your sensitive PHP code outside your htdocs directory. Instead, put in your htdocs directory a minimal PHP script that loads the rest of the code using include() or require().
An alternative is to put your MySQL credentials in a config file instead of PHP code at all. For example, the file format used by /etc/my.cnf and $HOME/.my.cnf is readable by the PHP function parse_ini_file(). It's easy to store your MySQL password outside of your code this way.
For example, read user and password from the [mysql] or [client] sections of /etc/my.cnf:
$ini = parse_ini_file("/etc/my.cnf", true);
if (array_key_exists("mysql", $ini)) {
$connect_opts = array_merge($connect_opts, $ini["mysql"]);
} else if (array_key_exists("client", $ini)) {
$connect_opts = array_merge($connect_opts, $ini["client"]);
}
$pdo = new PDO($dsn, $connect_opts["user"], $connect_opts["password"]);
Yes it seems insecure at first, but once you get the hang of it and know how to manage your files to minimize potential security breaches, you can minimize the risks associated with having passwords stored in plain text in potentially publicly exposed spaces. Yet AFAIK PDO doesn't even let you form a connection without supplying a password. The solutions are a combination of what everyone has said and then some. Here's my quick guide for what I do.
Separate SQL users for separate purposes (minimizes damage from SQL injection or hacked accounts):
There should be a PHP-specific user for each table you need to access. That user will be granted only enough rights to handle as much of that table that he needs to, if it doesn't need to delete then don't grant it delete. If it doesn't need to select then don't grant it select. It seems fussy but very quickly you'll have a copy-paste template to make the users, give them the right(s) they need, and document it. If there's a joined table, you'll want to also grant the user access to that table also, naturally.
-- a single user account for a specific purpose:
CREATE USER 'usermanager'#'localhost' IDENTIFIED BY '5765FDJk545j4kl3';
-- You might not want to give access to all three here:
GRANT SELECT, UPDATE, INSERT ON db.users to 'usermanager'#'localhost';
The purpose of this is so that if you have a bug in your code that lets people SQL inject, they won't be able to cause any harm beyond the scope of what that role can do.
Stupid mistake can reveal PHP code and files if left in-directory, move them out:
Never mind revealing the source code, even just trying to access php files "out of order" can be destructive.
Move as many files to an out-of-scope directory as possible. Then call them like so:
require_once('../lib/sql_connectors.php');
This should escape your html / webdir and you should hopefully be able to store all sorts of fun stuff outside the scope of what a stupid admin mistake could reveal.
You can even have a php file that gets pictures and videos from outside your webdir, that's how streaming sites protect their resources and also conduct php-based authentication to file access. To learn how to do that you'll want to look up assigning your own etag headers to make sure browsers cache your php-retrieved files otherwise you'll have a very busy server, here's a short introduction.
Block wrongful access to PHP that are left in-directory:
All of your in-directory PHP files can be protected by checking that the $_SERVER['REQUEST_URI'] isn't itself. If it is, you can have a function called show404() that loads the 404.php page and dies there or just directly call your 404.php with an include. That way, even if you have hackers trying to brute force your php files they'll never see them because they'll get 404 errors (fools the bots) and they'll see the 404 page (fools the humans).
I avoid using .php in any publicly visible paths, to do that, I make rewrite rules in my .htaccess files that look like this:
RewriteEngine On
RewriteRule ^login$ login.php [L,QSA]
The L makes it stop running other rules.
The QSA preserves the $_GET tags.
The first lines of code for every file (consider prepending) could be:
// they should be connecting via a redirect, not directly:
$fileName = basename(__FILE__);
if ($_SERVER['REQUEST_URI'] === '/' . $fileName) {
error_log('Security Warning: [' . $_SERVER['REMOTE_ADDR'] . '] might be trying to scrape for PHP code. URI: [' . $_SERVER['REQUEST_URI'] . ']');
include('404.php'); // should point to your 404 ErrorDocument
exit();
}
// redirect to actual file
include('../hidden/php/' . $fileName);
In this example, assuming you have the redirect in your .htaccess, a login.php with the code above, and a login.php in your hidden directory, the user would experience the following two scenarios: attempt to connect to '/login' and see the hidden '/login.php' page; attempt to connect to the visible '/login.php' directly and get a 404 error.
Those are the 3 big things, lots of small limited accounts to minimize damage in case of security failure, keep all possible files outside the web directory, and make all in-directory php files produce an error letting only non-php links access them.

PHP - retrieving application settings once from INI, but where should I store it for global use?

I am writing a very large application that requires an initial query of a DB or INI file to retrieve application settings. I then want to store it once globally so that I don't have to keep querying a DB or reading an INI file for every page load.
I have a pseudo bootstrap file that I include in every PHP file. Inside this bootstrap file, I initiate application paths, setup the session etc. I also want this file to perform the intial DB or INI read and store the application settings globally. I was thinking of using $_SESSION but I'm not so sure if this is a good idea or not.
The type of data that I want to store once globally: directory integration credentials (AD, Kerberos, etc), whether or not the server instance is behind a proxy, DB connection credentials, and whether or not logging is enabled or not. Additionally, I want the user to have deep control on what logs to keep: i.e. "when users log in", "when there is an error", "when a new calendar event is created", etc. These various logging actions occur throughout my application and I don't want to query the DB or read an INI each time to check whether a particular logging setting has been enabled.
Here is what I was thinking re: SESSION vars:
if( !isset($_SESSION["settings_retrieved"] ){
// begin DB or INI read here
$_SESSION["use_proxy"] = 1;
$_SESSION["ad_user"] = "authorized_user001";
$_SESSION["log_login"] = 1;
$_SESSION["log_error"] = 1;
// etc...
}
What do you think? Should I store these global application variables in SESSION?
your ini file is already a storage you're looking for.
So, keep it - you don't need anything else.
Sessions is not something ethereal. It's the same file or database record. So, you're going to make that filesystem or database lookup anyway, making your system overcomplicated with no real gain.

Secure password list in PHP

I'm thinking about storing list of passwords for users (eventually more info about them) of small-scale (max. 20 users) app in PHP file in directory like public_html_root/system/config/
<?php if($calledByApp !== true) die();
$pwds['username1'] = 'hispassword';
$pwds['username2'] = 'herpassword';
$pwds['username3'] = 'anotheroned';
?>
Now. hispassword is actually hashed version
$hashedpasword = sha1($password.sha1($salt));
This way, if file is included, it checks for $calledByApp, which is set upon starting from entry point - i.e. index.php in root, so we could say it's safe this way. If it's called directly from browser - it won't get served as text file, but rather as PHP file - and it will die also, since $calledByApp will return null or false.
Also, if another user is stored/deleted, the file gets rebuilt, so it reflects all users. And after including this file, we have all users in pretty array, so if we call
if (is_string($pwds[$sanitized_username])
&& ($pwds[$sanitized_username] === $sanitized_sha1_userpassword))
we'll do login.
My question is: Is this safe enough?
Clarification: DB for users seems to be a bit overkill - another table for max 20 users. Also, while this doesn't check if user is real, it won't do anything with DB - looks like added security too.
If for some reason mod_php has a hiccup it could result in httpd showing the uninterpreted file; store the script outside of the document root in order to fix this.
I would rather place that file outside of document root instead of relying on the PHP interpreter not failing for any reason.
No - this is a really bad idea.
By making your souce code files writeable you open a whole avenue for attacking your system.
Embedding data into source code is a messy practice - not least because it will not scale.
What happens if the file is locked for an update when a script tries to include it?
What happens when the connection to the browser is lost part way through writing the file?
If you're quite sure that you'll only ever have a very small number of users and a low level of concurrency then abetter solution by far would be to have a seperate directory, with all http access denied, containing one file per user, named with the username (or a hash of it if you prefer) containing the hashed password.
C.
It's always safer to store the encrypted passwords in a database.
If you are using a database then I would store user data in there. If not then I would look to start using one.

Categories