Monthly archives: November 2014

Uncaught exception ‘PDOException’ leaks database passwords

Posted on November 4, 2014 Comments

I am disappointed with a finding  related to PHP’s PDO library. I wrote a blog post a while back praising PDO in PHP for prepared statements and provided a migration guide.  I still 100% recommend PDO over the traditional and now deprecated libraries. This is not a bash post on PDO.

However, if you are not aware of the fact that if you are not catching the database connection exception when there is an error, your password will be revealed in the stack trace as long as display_errors is on. Now I understand that leaving display_errors on is considered bad practice. However, it can be quite useful in determining an error on-the-spot and when you hide “notice” based warnings (E_ALL ~E_NOTICE) the information provided is relatively benign.

I have never seen an error from a server-side scripting language like PHP reveal anything other than a function name, a file path, or just a line of code that wasn’t functioning correctly. These things can be mild security risks but they do not in any way leak credentials to the software.

The code I am working with:

I’ve set the PDO error mode to silent on purpose to show that even if you do that, this problem persists.

When trying to connect to database with wrong password:

Fatal error: Uncaught exception ‘PDOException’ with message ‘SQLSTATE[HY000] [1045] Access denied for user ‘root’@’localhost’ (using password: YES)’ in C:\server\data\localweb\test_pdo.php:3 Stack trace: #0 C:\server\data\localweb\test_pdo.php(3): PDO->__construct(‘mysql:host=127….’, ‘root’, ‘12345’) #1 {main} thrown in C:\server\data\localweb\test_pdo.php on line 3

When the database server is down or non responsive:

Fatal error: Uncaught exception ‘PDOException’ with message ‘SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it. ‘ in C:\server\data\localweb\test_pdo.php:3 Stack trace: #0 C:\server\data\localweb\test_pdo.php(3): PDO->__construct(‘mysql:host=127….’, ‘root’, ‘12345’) #1 {main} thrown in C:\server\data\localweb\test_pdo.php on line 3

When the database server is being powered off:

Fatal error: Uncaught exception ‘PDOException’ with message ‘SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it. ‘ in C:\server\data\localweb\test_pdo.php:3 Stack trace: #0 C:\server\data\localweb\test_pdo.php(3): PDO->__construct(‘mysql:host=127….’, ‘root’, ‘12345’) #1 {main} thrown in C:\server\data\localweb\test_pdo.php on line 3

When there are “Too many connections”:

Fatal error:  Uncaught exception ‘PDOException’ with message  ‘SQLSTATE[08004] [1040] Too many connections’ in C:\server\data\localweb\test_pdo.php(3) Stack trace:
#0 C:\server\data\localweb\test_pdo.php(3):: construct(‘mysql:host=127….’, ‘root’, ‘12345’) #1 {main} thrown in C:\server\data\localweb\test_pdo.php on line 3

Resolving the issue is simple, but as you can see, if your database has any type of very common error and you have display_errors turned on you are at risk for exposing your database password to the world. To fix it, just catch it in a try {} catch {} block or use set_exception_handler().

The reason I am bent out of shape about this is because I do not feel this should be expected behavior. The PHP team argues otherwise and says that display_errors has always been “dangerous” and should generally be disabled on production servers. This is true to an extent as I mentioned earlier. Regardless, the printing of a password in plain text in an error message is a poor choice. There is little reason to expose database password data in the stack trace and a whole host of reason not to. Error messages can be logged in all sorts of places and human error is made all the time, and with PDO being used on public-facing sites who may not have error messages disabled… what is the benefit? To verify that the username and password is correct?  If I need to see that, it can be done without the help of the stack trace.

PHP should “fix” this but as long as they take the hard stance of “use the software perfectly and you won’t get burned”, it won’t happen:

Yes, running production server with display_errors=on and printing out backtraces with argument is a security risk. That’s why you should never do it. — https://bugs.php.net/bug.php?id=62184

I will say that they do at least disclose this on the connections documentation. I missed this because I had followed a different tutorial elsewhere when learning about PDO. The importance of try { } catch statements are never emphasized either, so it’s easy to think about not having them if you’re just doing procedural programming (yes, exceptions are not limited to object-oriented, but seldom have I seen procedural code catching anything).