By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,871 Members | 2,337 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,871 IT Pros & Developers. It's quick & easy.

Database Security Issues

P: n/a
I'm helping someone to create an online database. All is fine and good
except for one problem. Here it is:

In order to provide connectivity to the database, I've created a file called
database.php which is readable only by the Apache web server.

It contained the following:

<?php

function database() {
$db = mysql_connect("localhost", "mtlstats", /* the password */);
mysql_select_db("mtlstats", $db);
return $db;
}

?>

I quickly realized that even though nobody could read the password from the
file, there was nothing preventing the other people with accounts on my web
server, from including this file into one of their own php scripts, and
hijacking the database. I therefore made a change, so that it would only
work when called from a file in the /mtlstats directory.

The file now reads as follows:

<?php

function database() {
if(strpos($PHP_SELF, "/mtlstats/") === 0) {
$db = mysql_connect("localhost", "mtlstats", /* the password */);
mysql_select_db("mtlstats", $db);
return $db;
}
return NULL;
}

?>

Unfortunately, I've discovered that although $PHP_SELF normally returns the
name of the file being processed by the server, when called from within a
function, it returns NULL for some reason. Can anyone suggest an
alternative means of correcting this problem?

Any assistance would be greatly appreciated.

--
Jonathan Lamothe
Founder of the Anime Void.
http://ani-void.cjb.net
Jul 17 '05 #1
Share this Question
Share on Google+
14 Replies


P: n/a
Jonathan Lamothe <jo**************@hotmail.com> wrote:
<?php
function database() {
if(strpos($PHP_SELF, "/mtlstats/") === 0) { [snip] }

?>

Unfortunately, I've discovered that although $PHP_SELF normally returns the
name of the file being processed by the server, when called from within a
function, it returns NULL for some reason. Can anyone suggest an
alternative means of correcting this problem?


RTFM, you need to brush up on your variable skills:

from
http://nl2.php.net/manual/en/languag...bles.scope.php
to
http://nl2.php.net/manual/en/languag...s.superglobals
to
http://nl2.php.net/manual/en/securit...terglobals.php
and
http://nl2.php.net/manual/en/reserve...riables.server

But the really shortshort version: use superglobals instead....

eg:
'PHP_SELF'

The filename of the currently executing script, relative to the document
root. For instance, $_SERVER['PHP_SELF'] in a script at the address
http://example.com/ test.php/foo.bar would be /test.php/foo.bar.

--

Daniel Tryba

Jul 17 '05 #2

P: n/a
Daniel Tryba wrote:
Jonathan Lamothe <jo**************@hotmail.com> wrote:
<?php
function database() {
if(strpos($PHP_SELF, "/mtlstats/") === 0) { [snip]
}


<moresnip>
But the really shortshort version: use superglobals instead....

eg:
'PHP_SELF'

The filename of the currently executing script, relative to the document
root. For instance, $_SERVER['PHP_SELF'] in a script at the address
http://example.com/ test.php/foo.bar would be /test.php/foo.bar.


It's often better to look at the value of $_SERVER['REQUEST_URI'], especially
if you're doing things with mod_rewrite that involve non-existent folder names
....
Jul 17 '05 #3

P: n/a
Jonathan Lamothe wrote:
I'm helping someone to create an online database. All is fine and good
except for one problem. Here it is:

In order to provide connectivity to the database, I've created a file called
database.php which is readable only by the Apache web server.

It contained the following:

<?php

function database() {
$db = mysql_connect("localhost", "mtlstats", /* the password */);
mysql_select_db("mtlstats", $db);
return $db;
}

?>

I quickly realized that even though nobody could read the password from the
file, there was nothing preventing the other people with accounts on my web
server, from including this file into one of their own php scripts, and
hijacking the database. I therefore made a change, so that it would only
work when called from a file in the /mtlstats directory.

The file now reads as follows:

<?php

function database() {
if(strpos($PHP_SELF, "/mtlstats/") === 0) {
$db = mysql_connect("localhost", "mtlstats", /* the password */);
mysql_select_db("mtlstats", $db);
return $db;
}
return NULL;
}

?>

Unfortunately, I've discovered that although $PHP_SELF normally returns the
name of the file being processed by the server, when called from within a
function, it returns NULL for some reason. Can anyone suggest an
alternative means of correcting this problem?

Any assistance would be greatly appreciated.


As long as others have access to the permissions of the account that the
web server is running as, then they will have access to any of your PHP
scripts (source code) and any files that your PHP scripts have
permission to read.

The trick is to not have users without your trust getting access to your
webserver's user. It's a system configuration issue.
Jul 17 '05 #4

P: n/a
Terence <tk******@fastmail.fm> writes:
As long as others have access to the permissions of the account that the
web server is running as, then they will have access to any of your PHP
scripts (source code) and any files that your PHP scripts have
permission to read.

The trick is to not have users without your trust getting access to your
webserver's user. It's a system configuration issue.


One way to protect database passwords is to remove them from the
code and have the web server set them in an environment variable
that the code could read. The web server would set a different
password depending on the user, directory, or whatever condition
you can think of; with Apache, for example, you could do this with
SetEnv, SetEnvIf, or mod_rewrite. Although the web server typically
runs as a non-privileged user such as "www" or "httpd", it usually
starts as root so it can bind to port 80. The passwords could be
stored in a file that only root can read, so PHP, CGI, or other
code running as the non-privileged web server user couldn't read
the passwords from the file.

Using the above mechanism, the only way a user could read other
users' passwords would be by reading the process memory, perhaps
using /proc/pid/mem on systems that have such a thing, or possibly
by getting the web server to dump core and then reading the core
file. The sysadmin should be able to prevent these possibilities
from happening.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/
Jul 17 '05 #5

P: n/a
Michael Fuhr <mf***@fuhr.org> wrote:
One way to protect database passwords is to remove them from the
code and have the web server set them in an environment variable
that the code could read. The web server would set a different
password depending on the user, directory, or whatever condition
you can think of; with Apache, for example, you could do this with
SetEnv, SetEnvIf, or mod_rewrite. Although the web server typically
runs as a non-privileged user such as "www" or "httpd", it usually
starts as root so it can bind to port 80. The passwords could be
stored in a file that only root can read, so PHP, CGI, or other
code running as the non-privileged web server user couldn't read
the passwords from the file.


Needlesly complicated. Run the webserver with the priveliges of a
user. That way the passwds can be in a file only readable to the user

--

Daniel Tryba

Jul 17 '05 #6

P: n/a
Daniel Tryba <ne****************@canopus.nl> writes:
Michael Fuhr <mf***@fuhr.org> wrote:
One way to protect database passwords is to remove them from the
code and have the web server set them in an environment variable
that the code could read. The web server would set a different
password depending on the user, directory, or whatever condition
you can think of; with Apache, for example, you could do this with
SetEnv, SetEnvIf, or mod_rewrite. Although the web server typically
runs as a non-privileged user such as "www" or "httpd", it usually
starts as root so it can bind to port 80. The passwords could be
stored in a file that only root can read, so PHP, CGI, or other
code running as the non-privileged web server user couldn't read
the passwords from the file.


Needlesly complicated. Run the webserver with the priveliges of a
user. That way the passwds can be in a file only readable to the user


Could you elaborate on how you'd do this on an ISP's web server
that has thousands of users? Apache 2's perchild MPM looks promising
for virtual hosts -- if you want to have a virtual host for each
user -- but according to the documentation it doesn't work yet on
most platforms, and I wonder how it would scale. It also doesn't
appear usable in a non-virtual-host setup, such as the ISP might
have for its SSL configuration.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/
Jul 17 '05 #7

P: n/a
Michael Fuhr <mf***@fuhr.org> wrote:
Needlesly complicated. Run the webserver with the priveliges of a
user. That way the passwds can be in a file only readable to the user
Could you elaborate on how you'd do this on an ISP's web server
that has thousands of users?


With apache it seem that suexec is the way to go (and thus introducing
new problems like running php as cgi, but the enhanced per user security
might be worth it).
Apache 2's perchild MPM looks promising for virtual hosts -- if you
want to have a virtual host for each user -- but according to the
documentation it doesn't work yet on most platforms, and I wonder how
it would scale. It also doesn't appear usable in a non-virtual-host
setup, such as the ISP might have for its SSL configuration.


On the system I run Apache/PHP I'm the sole user, on the only multiuser
system I have access to the server isn't Apache, it lacks "native" php
support so php is run as the user in cgi :)

--

Daniel Tryba

Jul 17 '05 #8

P: n/a
Daniel Tryba <ne****************@canopus.nl> writes:
Michael Fuhr <mf***@fuhr.org> wrote:
Needlesly complicated. Run the webserver with the priveliges of a
user. That way the passwds can be in a file only readable to the user


Could you elaborate on how you'd do this on an ISP's web server
that has thousands of users?


With apache it seem that suexec is the way to go (and thus introducing
new problems like running php as cgi, but the enhanced per user security
might be worth it).


As you point out, using suEXEC introduces problems of its own. One
of PHP's advantages is that it can be parsed directly by the server
without having to go through the fork/exec overhead of creating a
new process; using suEXEC or any other setuid/setgid mechanism that
requires a new process would negate that advantage. On a busy
server that could cause serious performance problems.

Run some benchmarks and compare the times for server-parsed PHP vs.
PHP run as CGI. Running as CGI is horrible.
Apache 2's perchild MPM looks promising for virtual hosts -- if you
want to have a virtual host for each user -- but according to the
documentation it doesn't work yet on most platforms, and I wonder how
it would scale. It also doesn't appear usable in a non-virtual-host
setup, such as the ISP might have for its SSL configuration.


On the system I run Apache/PHP I'm the sole user, on the only multiuser
system I have access to the server isn't Apache, it lacks "native" php
support so php is run as the user in cgi :)


This thread was about protecting passwords on a multiuser system,
a problem that ISPs and their customers face. Using suEXEC or other
setuid/setgid mechanisms can solve the security problem for the
user, but for the ISP they can cause unacceptable performance
degradation. The mechanism I posted is a way to protect passwords
without introducing the performance overhead of creating a new
process every time a page is served.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/
Jul 17 '05 #9

P: n/a
Michael Fuhr wrote:

This thread was about protecting passwords on a multiuser system,
a problem that ISPs and their customers face. Using suEXEC or other
setuid/setgid mechanisms can solve the security problem for the
user, but for the ISP they can cause unacceptable performance
degradation. The mechanism I posted is a way to protect passwords
without introducing the performance overhead of creating a new
process every time a page is served.


One way to do it, is to have a group for users with webpages, and make
the relevant directories chmod 0705 - then the user can access the directory,
apache can access it as nobody, and memebrs of the same group have no
access to the directory.

Just a thought...

Matt
Jul 17 '05 #10

P: n/a
Matty <ma*******@askmenoquestions.co.uk> writes:
Michael Fuhr wrote:

This thread was about protecting passwords on a multiuser system,
a problem that ISPs and their customers face. Using suEXEC or other
setuid/setgid mechanisms can solve the security problem for the
user, but for the ISP they can cause unacceptable performance
degradation. The mechanism I posted is a way to protect passwords
without introducing the performance overhead of creating a new
process every time a page is served.

One way to do it, is to have a group for users with webpages, and make
the relevant directories chmod 0705 - then the user can access the directory,
apache can access it as nobody, and memebrs of the same group have no
access to the directory.


If the web server can read a file then anybody who uses that web
server can potentially read that file. PHP features like safe_mode
and open_basedir can help prevent this, as can CGI mechanisms such
as suEXEC, but on some multiuser systems implementing such measures
isn't a viable option, and the web server may provide other services
that wouldn't be restricted these measures.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/
Jul 17 '05 #11

P: n/a
As others have noted, there's really no easy way you can protect the
file in question without making some serious changes to the Apache
setup.

The only solution I have think of is to encrypt the database password
using the login password as the key, and storing it in a associative
array on the server.

$passwords = {
"cleong" => "AB534BE432BEE433C...E433C340F",
"ojsimpson" => "7488494782...324239424",
"jausten" => "8492374837923...384274389"
...
}

When the user logs in, the password provided is use to decrypt the
cooresponding entry in the array, yielding the database password. The
password is then stored in a cookie on the client-side (can't use a
session variable, as session files are accessible through Apache).

Jonathan Lamothe <jo**************@hotmail.com> wrote in message news:<PB*******************@news20.bellglobal.com> ...
I'm helping someone to create an online database. All is fine and good
except for one problem. Here it is:

In order to provide connectivity to the database, I've created a file called
database.php which is readable only by the Apache web server.

It contained the following:

<?php

function database() {
$db = mysql_connect("localhost", "mtlstats", /* the password */);
mysql_select_db("mtlstats", $db);
return $db;
}

?>

I quickly realized that even though nobody could read the password from the
file, there was nothing preventing the other people with accounts on my web
server, from including this file into one of their own php scripts, and
hijacking the database. I therefore made a change, so that it would only
work when called from a file in the /mtlstats directory.

The file now reads as follows:

<?php

function database() {
if(strpos($PHP_SELF, "/mtlstats/") === 0) {
$db = mysql_connect("localhost", "mtlstats", /* the password */);
mysql_select_db("mtlstats", $db);
return $db;
}
return NULL;
}

?>

Unfortunately, I've discovered that although $PHP_SELF normally returns the
name of the file being processed by the server, when called from within a
function, it returns NULL for some reason. Can anyone suggest an
alternative means of correcting this problem?

Any assistance would be greatly appreciated.

Jul 17 '05 #12

P: n/a
ch***********@hotmail.com (Chung Leong) writes:
As others have noted, there's really no easy way you can protect the
file in question without making some serious changes to the Apache
setup.

The only solution I have think of is to encrypt the database password
using the login password as the key, and storing it in a associative
array on the server.
What login password are you using as the key?
$passwords = {
"cleong" => "AB534BE432BEE433C...E433C340F",
"ojsimpson" => "7488494782...324239424",
"jausten" => "8492374837923...384274389"
...
}

When the user logs in, the password provided is use to decrypt the
cooresponding entry in the array, yielding the database password. The
password is then stored in a cookie on the client-side (can't use a
session variable, as session files are accessible through Apache).


When what user logs in? This solution seems to assume that a single
user will be using the database and that the user will be logging
in using a password. How would this solution work for an application
that needs to access a database for any number of users who won't
be logging in?

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/
Jul 17 '05 #13

P: n/a
Michael Fuhr wrote:

One way to do it, is to have a group for users with webpages, and make
the relevant directories chmod 0705 - then the user can access the
directory, apache can access it as nobody, and memebrs of the same group
have no access to the directory.


If the web server can read a file then anybody who uses that web
server can potentially read that file. PHP features like safe_mode
and open_basedir can help prevent this, as can CGI mechanisms such
as suEXEC, but on some multiuser systems implementing such measures
isn't a viable option, and the web server may provide other services
that wouldn't be restricted these measures.


Well, really the only way to make it secure, if it needs to be, is to put
the site on its own server. If suExec is an option, that's another way to
do it.

Basically, if you have ${n}x100 users on a server, it's kinda hard to make
individual sites that secure, although open_basedir can help in php

If you need the security, you pay for it!

Matt
Jul 17 '05 #14

P: n/a
Yes, it's a limited solution. The assumption is that you have a small
group of trusted users accessing the database. I was trying to come up
with something that doesn't require changes to the server config,
since I doubt that an ISP would be willing to make them for you. Most
likely they'll just tell you to use their single-server or virtual
machine package.

mf***@fuhr.org (Michael Fuhr) wrote in message news:<3f**********@omega.dimensional.com>...
ch***********@hotmail.com (Chung Leong) writes:
As others have noted, there's really no easy way you can protect the
file in question without making some serious changes to the Apache
setup.

The only solution I have think of is to encrypt the database password
using the login password as the key, and storing it in a associative
array on the server.


What login password are you using as the key?
$passwords = {
"cleong" => "AB534BE432BEE433C...E433C340F",
"ojsimpson" => "7488494782...324239424",
"jausten" => "8492374837923...384274389"
...
}

When the user logs in, the password provided is use to decrypt the
cooresponding entry in the array, yielding the database password. The
password is then stored in a cookie on the client-side (can't use a
session variable, as session files are accessible through Apache).


When what user logs in? This solution seems to assume that a single
user will be using the database and that the user will be logging
in using a password. How would this solution work for an application
that needs to access a database for any number of users who won't
be logging in?

Jul 17 '05 #15

This discussion thread is closed

Replies have been disabled for this discussion.