How to protect Database?

Earlier we agreed that if you can see “config.php” (inside Web Root) - which points to “database_settings.php” (outside the Web Root) then that sorta defeats the purpose.

Now you are implying that if I move “config.php” to outside the Web Root, but point to it from all of my scripts that would help.

But you are still leaving a trail to my “database_settings.php” file!!

As I see it, for this to work, I need a way to hide the details of where “config.php” and “database_settings.php” are located to calling scripts, otherwise nothing is being accomplished that I don’t already have. (Although I get that at least you can’t easily surf there via HTTP.)

Follow me?

Debbie

The only way an attacker would know the trail is if they already had access to your system via FTP, SSH, or something similar. At that point, you are screwed no matter what, as they already have physical access.

There would be no way for them to get the location of your files without one of the following:

  1. A way to upload a script and execute it
  2. Physical Access

Since the path would be hard coded (not part of a variable), they couldn’t use an include/require command to get access to the variable to see where the files are located. They’d have to use one of the above techniques to get to it, and if they did that, they could do FAR worse to you than get the path of a few files.

I get SOOOO WORRIED about security on my website… :frowning: :frowning: :frowning:

(According to a tech I was chatting with last night at GoDaddy, it is possible for a hacker to “jump the shark” and get into directories above the Web Root. And I’m convinced that the NSA and the Chinese can do ANYTHING!!!)


So you are saying that if I hard-code an Include like this…


	require_once('/var/www/vhosts/MySite.com/SECRET_FOLDER_OUTSIDE_ROOT/database_settings.php');

…in each of my scripts, then there is no practical way for a hacker to SEE that path or to FOLLOW that path by “traditional” hacking via HTTP, right??

I guess I come back to the circular logic that started all of this…

Based on that, let’s say I have “index.php” with my Include noted above.

And let’s ay that PHP pukes, and exposes all of the file’s content out in plain site. (As Mittineague said, unlikely, but possible.)

So now the hacker knows that I have “the goods” located here…


	require_once('/var/www/vhosts/MySite.com/SECRET_FOLDER_OUTSIDE_ROOT/database_settings.php');

So, while I protected the “database_settings.php” file itself, I still somewhat exposed it, because I didn’t protect its location in any scripts including it…

Now that the hacker knows the new location of “database_settings.php”, they can start trying to hack into that directory outside of my Web Root.

Would that be hard to do? Probably.

But according to the guy at GoDaddy last night, it is possible.


I guess what I am trying to figure out, is this…

Is there a way to move sensitive files OUTSIDE of the Web Root, give them a “name” or “pointer” that all scripts in the Web Root can see, but which do not expose where the sensitive files are located? (Almost like a one-way mirror!!)

Follow me?


In another thread of mine, people were saying that PHP Constants are “global”, but I don’t think that is true since you have to Include them in order for them to be seen.

It would be nice if outside the Web Root I could do this…

DATABASE_SETTINGS = ‘/var/www/vhosts/MySite.com/SECRET_FOLDER_OUTSIDE_ROOT/database_settings.php’;

And then in any script, just say…


	require_once(DATABASE_SETTINGS);

That way, when some script says the “magic word”, the PHP gods from above know to link the file from above the Web Root to the script in the Web Root, but anyone who get’s access to the script’s contents would only see the obscure reference to…


	require_once(DATABASE_SETTINGS);

Follow my line of thinking?

[ot]I know most people don’t care or think I’m paranoid, but I’m telling you that hackers in 2013 have taken the game to a WHOLE NEW LEVEL, and what was sufficient 5 years ago just doesn’t cut it today!!

And if I am ever going to finish this website and get it online, and let thousands of innocent people trust their sensitive info with my website and database, then I want to go above and beyond the call of duty and really go out of my way to protect people’s info!!!

Like everything out there, I am sure there are better solutions, it is just a real challenge to try and out-fox modern day hackers?! :eek:
[/ot]

So, sorry for wanting the world, but I just see so many websites fail these days, and I don’t want to take any shortcuts and then later jeopardize my customers’ data…

To date, it has been my experience that if I try hard enough, I have always been able to find solutions that are rock-solid and that keep things safe.

But on this thread, I obviously need some help!! :blush:

Sincerely,

Debbie

Keep it offline? If it isn’t ever online, it can’t be hacked right? (yes, this is a joke)

Yes, that is called a directory traversal attack. In short, consider the following code (which is INSECURE - DON’T USE IT)
HTTP request sent: test.php?path=…/…/…/

$path = $_GET['path'];
require_once("$path/myfile.php");

Or with register globals enabled: (file named test.php – HTTP request sent test.php?path=…/…/)

require_once("$path/myfile.php");

Without being able to upload a script an execute it on your server, or physical access, yes that is what I’m saying. At least, I don’t know of a way.

All ways to improve it, usually involve putting the path in a variable, that variable then becomes accessible and thus a point of risk. If you want to do that, that’s fine (as the person will have to guess the variable name), but if you truly wanted to limit your risk, hard code it.

cpradio,

You’re too fast for me today!

I was still editing…

What about my “pointer” idea?

Sincerely,

Debbie

Yes, but if I can read your file, you’ve got bigger problems than worrying about the location of your files. Next time you have it up, I potentially know all of the SQL, XSS, and other vulnerabilities of your site (as I was shown the source code). I also know variable to use to include your database settings, so I could simply execute a script that read the contents of DATABASE_SETTINGS and wrote it out, thus seeing what the file contains.

If you see value in that approach, use it. But if you have a file injection vulnerability, then outputting the value of DATABASE_SETTINGS is child’s play.

Moot point. In 5 more years, the hackers of today will be put to shame by the hackers of 2018. If you sit and wait for a perfect site, you’ll never publish anything, as there is no such thing (just read the news).

There is nothing wrong with wanting the world, until you get to the point of an unobtainable goal. You are at that point. You need to start moving forward. Establish procedures for resetting customer passwords (if they would get breached), etc.

I’m scared… :frowning:

So let me re-cap… (Boy is my brain on overload!!)

1.) Moving my “database_settings.php” to outside the Web Root is a win-win.

2.) Moving my “config.php” to outside the Web Root wouldn’t hurt, but is debateable.

3.) Having any scripts located inside the Web Root, reference my database settings file like this is okay…


	require_once('/var/www/vhosts/MySite.com/SECURE_FOLDER_OUTSIDE_ROOT/database_settings.php');

4.) Having any scripts located inside the Web Root, reference my database settings file like this would not (?) be okay…


	require_once('../outside_webroot/database_settings.php');

5.) If a hacker was able to get access to the contents of any PHP script, I would have a larger issue at hand than just that they were able to see the path to where my Database Settings are now located outside of the Web Root, right?

Sincerely,

Debbie

1-3) Yes, I agree.

  1. is perfectly okay too, so take your pick between #3 and #4.

  2. Yes, as they found a way in, via physical access or some sort of vulnerability in your site. You need to be focused on how they got in, so you can plug it quickly.

Using mysql_real_escape_string on each variable will help you.

Not in this case it won’t as we are talking about SQL Injection protection. Next time, take time to read the thread before posting your response.

This is how you protect your database. In this case of this thread, There is nothing to worry about with the above code…

There are multiple ways of protecting your database, from physical access, sql injections, and limiting the security of the users who can hit it. mysql_real_escape_string is a bad answer anyway, as it dictates you continue using a deprecated feature in PHP. Instead mysqli or PDO should be used, which give you much more tools in protecting against sql injections.

cpradio,

How about this strategy to tie together all we have discussed…

I create the following directory structure…


secure_outside_webroot
	config.php
	database_settings.php

web_root
	index.php

Then inside the following files, I have this…

index.php


<?php
	// Initialize Session.
	session_start();

	// Access Constants.
	// (This would have to be adapted depending on the location of the script!!)
	require_once('../SECURE_OUTSIDE_WEBROOT/config.php');

	// Connect to Database.
	require_once(DATABASE_SETTINGS);

	// Do something with Database Connection...

config.php


	// Website Environment
	define('ENVIRONMENT', 'development');
//	define('ENVIRONMENT', 'production');

	// Physical Location (aka Document Root)
	define('WEB_ROOT', ENVIRONMENT === 'development'
			? '/Users/user1/Documents/DEV/++htdocs/06_Debbie/'
			: '/var/www/vhosts/MySite.com/httpdocs/');

	// Virtual Location
	define('BASE_URL', ENVIRONMENT === 'development'
			? 'http://local.debbie'
			: 'http://www.MySite.com');

	// Database Settings
[COLOR="#FF0000"]	// (Note: The THEN branch really needs to be an Absolute Path, but I'm not sure how to do that in NetBeans yet?!)[/COLOR]
	define('DATABASE_SETTINGS', ENVIRONMENT === 'development'
			? '../SECURE_OUTSIDE_WEBROOT/database_settings.php''
			: '/var/www/vhosts/MySite.com/SECURE_OUTSIDE_WEBROOT/database_settings.php');

database_settings.php


	define('DB_ENVIRONMENT', 'development');
//	define('DB_ENVIRONMENT', 'production');

	// Database Host.
	define('DB_HOST', DB_ENVIRONMENT === 'development'
			? 'localhost'
			: 'production_blah');

	// Database User.
	define('DB_USER', DB_ENVIRONMENT === 'development'
			? 'root'
			: 'production_blah');

	// Database Password.
	define('DB_PASSWORD', DB_ENVIRONMENT === 'development'
			? 'root'
			: 'production_blah');

	// Database Name.
	define('DB_NAME', DB_ENVIRONMENT === 'development'
			? 'doubledee'
			: 'production_blah');

	// Make the connection.
	$dbc = @mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME)
					OR die('Could not connect to database.  Contact System Administrator.');

Here is my thinking…

1.) Database Settings are outside of the Web Root, and safer.

2.) Config Settings are outside of the Web Root, and safer.

3.) Includes in my scripts only gives location of Config file, but the Config file contents are in theory still safe.

4.) The Constants “WEB_ROOT” and “BASE_URL” would not reveal the paths to which they refer. (Unless a hacker got outside of the Web Root.)

5.) The Constant “DATABASE_SETTINGS” would not reveal the path to which it refers. (Unless a hacker got outside of the Web Root.)

If I can get the RED comments above fixed, then I think this works pretty well?!

What do you think about all of this?

Sincerely,

Debbie

I’m not following, what does NetBeans have to do with being able to use an absolute path?

Looks good to me, you have an extra ’ in your config for your THEN statement for DATABASE_SETTINGS

You’re gonna make me type all of this out, aren’t you?! (:

Okay, rewind…

Most of my problems with paths and includes and security have largely hinged on the fact that I have been unable in the past to make my NetBeans environment the same as my Production environment.

Here is some background on NetBeans…

In NetBeans, everything is based on “Projects”.

So my current endeavor is in the Project called “06_Debbie”.

In each “Project”, are two things…


Source Files (Folder??)

Include Path (???)

The “Source Files” acts as your Web Root by default and is where all of my scripts reside.

Unfortunately, there is no way in NetBeans to create a directory outside of the “Source Files” directory. And that means that I have DISPARATE environments between DEV and PRODUCTION!! :nono:

Because I am persistent as hell, I kept playing around with things until 2:00a.m. this morning, and here is what I discovered…

I created a new Test Project called “_Test”

Option #1:
On my Hard-Drive I create a folder called “_SECURE_OUTSIDE_WEBROOT”.

Inside of it I place a dummy “database_settings.php” file.

Next in NetBeans, under “Include Path” I mapped to the file above located on my HDD.

After doing this, it appears that an Include to said location is recognized by Netbeans…


	require_once('/Users/user1/Documents/DEV/_SECURE_OUTSIDE_WEBROOT/database_settings.php');

So that appears to be one way to maybe simulate having a directory outside of the Web Root in Development…

Option #2:
This one is trickier, but I sorta like it better…

In my “_Test” Project, I created the following sub-folders inside of “Source Files”…


outside_webroot

web_root

Then in NetBeans’ Preferences, I did this…


[b]Sources:[/b]
[b]Project Folder:[/b] /Users/user1/Documents/DEV/++htdocs/_Test

[b]Source Folder:[/b] /Users/user1/Documents/DEV/++htdocs/_Test

[b]Web Root:[/b] web_root  [COLOR="#FF0000"](The default value was "<source folder>" but I changed it.)[/COLOR]


[b]Run Configuration:[/b]
[b]Project URL:[/b] http://local.test

[b]Index File:[/b] index.php

Then in my Virtual Host files, I mapped things so that [http://local.test points to /Users/user1/Documents/DEV/++htdocs/_Test/web_root.

Doing all of this for Option #2 - which was no small feat!!! - seems to simulate what I would have in Production. That is, a Web Root directory and a directory which is outside of the Web Root.

(Not sure if either of these options is legit?!)

So on to your question, CPRadio…

If you look at the red text in my last post, you will see that if I am in DEVELOPMENT, I need a way for the constant DATABASE_SETTINGS to point to an absolute location, because otherwise, as different files in different locations reference this Constant, it reek havoc having a Relative Reference versus an Absolute Reference.

And I haven’t had time to figure out if I can use an Absolute Reference to the “outside_webroot” sub-directory in my “Source Files” folder in NetBeans.

Follow me?!

Whew!!! (:

Sincerely,

Debbie

Okay, I’m installing NetBeans, as I don’t understand why you can setup a directory like so:

– httpdocs/
-----index.php
-----includes/
– mysecurefolder/
-----config.php
-----database_settings.php

Okay, here is what I did with NetBeans.

I first created the following folder structure
C:\MySite.com
C:\MySite.com\httpdocs
C:\MySite.com\secure

Then I created a new NetBeans project, choose PHP with existing Sources
I selected C:\MySite.com as the sources folder
Clicked Finished

And now I have a project that looks like:

  • Source Files
    • httpdocs
    • secure
  • Include Path

So if I had to guess, you may need to setup a NEW project for NetBeans to work the way you want it to with your secure directory approach.

Thanks for going above and beyond the call of duty!! :tup:

Okay, I just learned something here.

I had no idea that is what PHP with existing Sources did?! :eek:

Ironically, though, what you just did with NetBeans is what I did last night manually as described in my “Option #2” above.

Same end effect, other than NetBeans automated some of the process for you!


I still need to tweak how I set the DATABASE_SETTINGS constant for NetBeans, though…

Sincerely,

Debbie

cpradio,

Okay, I think I finally have things figured out and working.

Here is what I did…


As stated before, I created this in Netbeans last night…


_Test
	secure_outside_webroot
		config.php
		database_settings.php

	web_root
		index.php

index.php


<?php
	// Access Constants.
	require_once('../secure_outside_webroot/config.php');

	// Connect to Database.
	require_once(DB_SETTINGS_PATH);


	$username = 'DoubleDee';


	// Build query.
	$q1 = "SELECT id, email, username
						FROM member
						WHERE username = ?";

	// Prepare statement.
	$stmt1 = mysqli_prepare($dbc, $q1);

	// Bind variable to query.
	mysqli_stmt_bind_param($stmt1, 's', $username);

	// Execute query.
	mysqli_stmt_execute($stmt1);

	// Store results.
	mysqli_stmt_store_result($stmt1);

	// Check # of Records Returned.
	if (mysqli_stmt_num_rows($stmt1)==1){
		// Message Found.

		// Bind result-set to variables.
		mysqli_stmt_bind_result($stmt1, $id, $email, $username);

		// Fetch record.
		mysqli_stmt_fetch($stmt1);
	}

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
	<title></title>
</head>

<body>
	<?php
		echo "<p>The user you requested from the database is: <b>$username</b></p>";
	?>
</body>
</html>

secure_outside_webroot/config.php


<?php

	// Website Environment
	define('ENVIRONMENT', 'development');
//	define('ENVIRONMENT', 'production');

	// Physical Location (aka Document Root)
	define('WEB_ROOT', ENVIRONMENT === 'development'
			? '/Users/user1/Documents/DEV/++htdocs/_Test/web_root/'
			: '/var/www/vhosts/MySite.com/httpdocs/');

	// Virtual Location
	define('BASE_URL', ENVIRONMENT === 'development'
			? 'http://local.debbie'
			: 'http://www.MySite.com');

	// Database Settings
	define('DB_SETTINGS_PATH', ENVIRONMENT === 'development'
			? '/Users/user1/Documents/DEV/++htdocs/_Test/secure_outside_webroot/database_settings.php'
			: '/var/www/vhosts/MySite.com/secure_outside_webroot/database_settings.php');

?>

(Notice how I made the “THEN” branch of the last DEFINE an Absolute Path, thus solving my earlier issue!!!)

secure_outside_webroot/database_settings.php


<?php
	define('DB_ENVIRONMENT', 'development');
//	define('DB_ENVIRONMENT', 'production');

	// Database Host.
	define('DB_HOST', DB_ENVIRONMENT === 'development'
			? 'localhost'
			: 'production_blah');

	// Database User.
	define('DB_USER', DB_ENVIRONMENT === 'development'
			? 'root'
			: 'production_blah');

	// Database Password.
	define('DB_PASSWORD', DB_ENVIRONMENT === 'development'
			? 'root'
			: 'production_blah');

	// Database Name.
	define('DB_NAME', DB_ENVIRONMENT === 'development'
			? 'doubledee'
			: 'production_blah');

	// Make the connection.
	$dbc = @mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME)
					OR die('Could not connect to database.  Contact System Administrator.');

?>

When I run index.php

This is the URL:

http://local.test/index.php

This is the output:

The user you requested from the database is: DoubleDee

I think I have a winning solution…

Advantages of New Approach:

1.) Directory Structure is the same in DEV and PRODUCTION environments!!

2.) Database Settings are now safer outside of Web Root.

3.) Config File is now safer outside Web Root.

4.) File Paths assigned to Constants are hidden because they are stored in the “config.php” file which is outside the Web Root.

5.) File Path to “database_settings.php” is hidden because it is also stored in the “config.php” file which is outside the Web Root.

6.) Include syntax for Database Connection is shortened slightly and thus simplified.

What do you think??

See anything that might be a SECURITY RISK??? :-/

Sincerely,

Debbie

With what you posted, no, I don’t see any security risk.

I’m glad to hear you got it all resolved and matching your Prod environment.