UPDATE 2: Thanks to Chris Shiflett, who provided a link to a real answer in his comment. Clearly, the way to do this within the environment where you have one host and lots of ~users is to use .htaccess. Each user would define in their own /home/user/public_html/.htaccess two environment variables like so:
SetEnv DBUSER mysqluser
SetEnv DBPASS mysqlpass
PHP will get these variables passed in the $_SERVER superglobal as $_SERVER['DBUSER'] and $_SERVER['DBPASS'].
Even better, if the .htaccess is then chowned by an admin to the nobody user and then chmod 0600, it will be unviewable in the shell by anyone but root and apache. It would also be trivial to implement and provide a setuid tool such as "vicrontab" to modify .htaccess if necessary.See Chris Shiflett's last comment on this error
In this way, scripts would look like so:
< php
$db = mysqli_connect('localhost', $_SERVER['DBUSER'], $_SERVER['DBPASS']);
>
This yields completely secure mysql user/pass per-user in a shared environment with 1 virtual host and lots of users who all have shell access.
Two days ago, I gave a talk at the University of Nebraska-Lincoln's computer science department colloquium on open source. At the reception preceding the talk, one of the students asked if there was a good way to protect the user/password of his MySQL scripts. This is an issue I have never run up against because we have a unique IP on the webhost, and it doesn't matter whether someone knows the user/pass, they can only connect directly from that host (and if someone can hack into the host, I doubt the database is the only thing that will be compromised).
Our student, however, had been browsing student accounts and noticed that one student had a particularly attractive webpage that couldn't have been coded by the student. It turned out to be an install of wordpress, so he thought he might give it a try. While installing the program, he noticed that the MySQL username/password was stored in plaintext in a wp-config.php file (or something of that nature), and so thought "hmm, I wonder if other UNL students can see the password." To test, he tried "cat /home/user/public_html/wordpress/wp-config.php" and sure enough: there it was in plain sight. This would not be an issue were it not for the fact that every student runs on the same site, and so all have access to the same mysql space, all they need is the password.
Having never run into this issue before, I came up with a PHP-based solution, and a MySQL-based solution, but neither makes me tremendously happy, so I wonder if any of you have a working solution to this problem in place
What I came up with was:
- each user's web space has its own virtual host that is used to grant mysql privileges, so instead of "http://www.example.com/~user" we would have "http://user.students.example.com". In this way, it is not possible to connect to the mysql server unless you are accessing it directly from the web host. This, however, is likely to prevent the usage of the command-line mysql program, as it will attempt to connect from localhost.
- The password is saved in a read-only file that is created by the web server itself.
The second method works in tandem with an
open_basedir restriction in php.ini to the user's home directory. Basically, how it works is this simple system:
- First assume our user is named "joeshmoe" and the user has shell access to /home/joeshmoe, and web root is /home/joeshmoe/public_html, the mysql password is 'mysqlpassword', and we are using PHP 5
- login as joeshmoe to the unix shell
- mkdir /home/joeshmoe/passwords
- chmod 0777 /home/joeshmoe/passwords
- save this script as /home/joeshmoe/public_html/savepassword.php:
< php
file_put_contents
('/home/joeshmoe/passwords/mypass.php',
'mysqlpassword');
chmod(0600,
'/home/joeshmoe/passwords/mypass.php');
>
- browse to "http://www.example.com/~joeshmoe/savepassword.php"
- chmod 0000 /home/joeshmoe/passwords
- rm /home/joeshmoe/public_html/savepassword.php
At this point, to use the password, all you need to put in your scripts is "file_get_contents('/home/joeshmoe/passwords/mypass.php')" instead of "'mysqlpassword'", and only the webserver will be able to read the file. open_basedir will make it impossible for any external scripts to read the password.
Any comments