Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I've read the advice (example: store them in php file in a location inaccessible as a URL) but can't help thinking there must be a better way of storing/accessing database credentials.

Ideally it would be impossible for someone with access to the webserver files to obtain the database credentials. This leaves the challenge of how the webserver gets a database connection...

If there was a way to pass a PDO connection object between two unrelated scripts, it might be possible.

e.g.

  1. main website script, running as www-data needs a db connection

  2. somehow makes a call to a php function that exists in a file that is unreadable by www-data.

  3. that function decides whether the script should be allowed to access the database (e.g. uses a debug backtrace, creates md5sums (or similar) of all the files mentioned, compares them against protected, known-good, ones) and if it passes this test, establishes a connection and returns the PDO object.

  4. main web script is able to use the PDO object, but cannot extract the credentials.

Is there a way to create a PHP library that is loaded before, but outside of the main script execution? e.g. add to stock libs? This would make this sort of thing possible.

Or is there a better way?

share|improve this question

2 Answers 2

up vote 2 down vote accepted

If your attack model allows "attackers to upload their own scripts", then they have access to everything those same script can see or do, and "secure access to database", for this value of secure, is simply not possible.

(Short of redesigning the database so that it can run a check on all PHP files involved in a given connection - while theoretically possible, it would be exceedingly difficult - just think what it means to identify the PHP scripts, included by a Web process, that opened a connection, of which the DB server only knows the source address and port! - and very likely a performance killer)

But at this point you can move some logic away from the webserver, taken as unreliable, and see what security can be found elsewhere.

For example, you can make it so the different web application access levels use different credentials - you might have three database users "guest", "user" and "admin". You can organize things so that, for example, user administration by the user admin is not done on the same web server (you can separate it by process user, on a different webroot, another VM, or a physically separated web server).

Most functions and queries you can replicate using high-privileged procedures and functions that can access underlying data to which the web users have no access: for example you can do login checks with a function:

DELIMITER //
CREATE FUNCTION is_valid_user(user varchar(32), pass varchar(32))
returns BOOLEAN
DETERMINISTIC SQL SECURITY DEFINER
BEGIN
DECLARE ret BOOLEAN;
SELECT 1 = COUNT(*) INTO ret FROM users WHERE user = username AND MD5(pass) = password;
RETURN ret;
END//
DELIMITER ;

The Web application as user web has EXECUTE privilege, but has no SELECT/INSERT/DELETE privileges on the users table. So it can't enumerate users, or reset all the passwords in one fell swoop,

It is even possible (but not very useful, since ability to upload executable scripts makes an almost ideal man-in-the-middle scenario) to use the guest account to retrieve the web access credentials, stored in the users table, provided that the Web user has the correct password:

  1. user John logs in with password 'Doe'. Web application is running as guest
  2. the function get_credentials('John','Doe') returns 'web:myfirstpass'
  3. Web application switches credentials to web, and has now access to more features

All data logging is INSERT only (only the admin can delete log records), and access to important/"financial" data (e.g. an invoice table) can be done by running all ops on a temporary table owned by web, while a privileged procedure can be used to finalize and validate the table, and copy it into invoices.

With a bit more work, the user can be associated with a highly random 'security identifier' string that is unique to him. Only by supplying that security identifier can he access procedures that retrieve invoices; and those procedures will only select invoices with that same identifier.

This way - a very labor-intensive way, admittedly - an attacker can only access the data of those users that log in, and are tricked out of their credentials, on the compromised web server.

You're left with the problem of quickly reacting to such a compromise.

On a Linux server with inotify, it would be possible to continuously monitor files and remove those that are not "approved" (i.e. their SHA1 hash is not in the "allowed" list). Any modification or addition to monitored files would trigger their removal as well as an alert being sent to the administrator:

inotify: '/srv/www/padma/htdocs/ CREATE dfqjkw.php'
inotify: '/srv/www/padma/htdocs/ MODIFY dfqjkw.php'
inotify: '/srv/www/padma/htdocs/ CLOSE_WRITE,CLOSE dfqjkw.php'
ANOMALY: '/srv/www/padma/htdocs/dfqjkw.php' (SHA: e0a6bf9020320dca178cf115da4fa26de0278a25cf41702d667988877cdbc2d1) is neither known nor in testing
inotify: '/srv/www/padma/htdocs/ DELETE dfqjkw.php'
ACTIONS: '/srv/www/padma/htdocs/dfqjkw.php' targzipped, sent to root, and removed

This would also require a pretty bit of tweaking for people uploading their web sites - you'd need a "test" FTP web site where the upload takes place, and an "approval" procedure by which each file's signature is extracted and the web site is copied onto the "production" filesystem, effectively doubling data usage.

On the other hand, stealing FTP credentials as many trojan malware does would be no longer useful: lacking the approval procedure, the compromised files would only be present on http://test.www.mysite.com, which would only be accessible from a few selected networks, not on http://www.mysite.com which is allowed to all.

share|improve this answer

You could make an internal website only accessible to localhost that would pass the credentials to the main PHP script and thus the file would be inaccessible to the main site's user context and would only be stored in memory, but that's probably overkill for most purposes.

If you put the configuration in a file that isn't accessible directly from the web and limit the connections to being from only the web server, you are pretty strongly protected since they would have to hijack the web server to execute attacks other than SQL Injections (and if they can SQL inject, they are going to be able to access the same credentials the site legitimately uses).

share|improve this answer
    
What this achieves is ensuring only valid code can use a pdo object. Frequently, attackers will upload their own scripts, then gain access to the DB credentials stored in a file, then use credentials in their own scripts to obtain access. –  artfulrobot May 21 '13 at 16:01
    
@artfulrobot - right, but if they can upload their own scripts, then you are sunk no matter what you do as their scripts can impersonate your valid scripts and get the same object. The only alternative would be to do a nested SOAP type service for all the data and have a SOAP based DAL that is isolated from the general web. –  AJ Henderson May 21 '13 at 16:22
    
They couldn't impersonate my scripts if every script was tested against a hash, though... –  artfulrobot May 21 '13 at 19:53
    
@Artfulrobot If they can't impersonate your scripts, then they can't access the configuration either. –  AJ Henderson May 21 '13 at 19:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.