If my mongo database is down, my php application is printing out the plaintext password in the error. How can I prevent this?
Fatal error: Uncaught exception 'MongoCursorException' with message
'couldn't send command' in /ap/db.php:23 Stack trace:
#0 /ap/db.php(23): MongoDB->authenticate('username', 'actual_password')
#1 /ap/index.php(6): Worker->__construct() #2 {main} thrown in /ap/db.php
on line 23
I understand that I can disable php errors, but that is not what I want to do. I want to see an error, but I don't want it to print the password.
In a production application, users should never see an error like "Uncaught exception" or other developer-oriented message. This exposes a lot of information to a potential attacker and confuses your legitimate users. Log the detailed technical message and display a friendly error page to the user.
To disable visible errors and log them instead, edit php.ini:
Set error_log to a valid log path
Set display_errors to Off.
The process to enable friendly errors depends on your web server, but the idea is the same: Set a custom page to be displayed when a 500 error is encountered. In Apache, for example, you set ErrorDocument 500 /path/to/custom/500.html.
EDIT :
OP indicates that this is a development box — either way you should wrap your connection attempt in a try/catch block (which is something you should be doing anyway), and then you can display a 'sanitized' error message:
try {
MongoDB->authenticate('username','password');
} catch (MongoCursorException $e) {
die("Unable to authenticate to database [code: " . $e->getCode() . "]: "
. $e->getMessage());
}
Related
I am trying to connect to the database, and when I try with everything correct, the database connects, and everything is fine. But, when I try to connect using some wrong credentials, it throws an error message, and I am figuring out a way to hide the error message from the user.
function connectDatabase(){
$dbServerName = 'local_host';
$dbUsername = 'root';
$dbPassword = '';
$dbName = 'kishor_me';
$conn = mysqli_connect($dbServerName, $dbUsername, $dbPassword, $dbName);
if (!$conn) {
echo "error message";
}else{
echo "success message";
}
}
I tried to use the mysqli_connect_errno() and mysqli_connect_error(), but that also returned the same error.
I am not trying to get rid of this error by correcting the error now, which is by changing "local_host" to "localhost".
And I am getting the following error message now.
Warning: mysqli_connect(): php_network_getaddresses: getaddrinfo for local_host failed: No such host is known. in C:\Xampp\htdocs\test.php on line 17
Fatal error: Uncaught mysqli_sql_exception: php_network_getaddresses: getaddrinfo for local_host failed: No such host is known. in C:\Xampp\htdocs\test.php:17 Stack trace: #0 C:\Xampp\htdocs\test.php(17): mysqli_connect('local_host', 'root', '', 'kishor_me') #1 C:\Xampp\htdocs\test.php(28): connectDatabase() #2 {main} thrown in C:\Xampp\htdocs\test.php on line 17
I also tried
mysqli_report(MYSQLI_REPORT_OFF);
and it shows the following error now:
Warning: mysqli_connect(): php_network_getaddresses: getaddrinfo for local_host failed: No such host is known. In C:\Xampp\htdocs\test.php on line 17
Warning: mysqli_connect(): (HY000/2002): php_network_getaddresses: getaddrinfo for local_host failed: No such host is known. in C:\Xampp\htdocs\test.php on line 17
error message
Now I have used the following command to hide the error message:
ini_set('display_errors','0');
Now it is throwing an HTTP 500 error.
Isn't there any way I can show the user the critical error message and not the other error description generated by the language and also not give an HTTP 500 error? Please let me know if there is any way or if this question has already been answered.
It seems you are using some outdated tutorial, that offers incorrect approach at reporting errors: a code that tries to detect the connection error manually and output something on its own. But your code shouldn't be doing anything like that. Mysqli can report errors automatically and database errors are no different from other errors, and therefore do not require any special treatment.
Let's answer your question step by step:
How to detect a connection error
In the ancient times, some 10 years ago, PHP used mysql extension to talk to MySQL database, which was unable to handle errors automatically, and every database operation had to be checked for errors manually. That's where this if (!$conn) { stuff is coming from. But this library is long gone, and PHP got a new one, mysqli. Which has the ability to raise errors automatically, just like any other command in PHP, include or header() for example. You aren't checking every include or header() result manually, are you? So you shouldn't with mysqli.
As you can see, mysqli_connect() produces the error automatically, just like any other function. So there must be no if (!$conn) { part in your code. Neither on connect, nor with query() or any other mysqli function.
In a nutshell: you don't need any code to detect database errors. They are regular errors now. And, if you think of it, not only database errors must be hidden. Any other error, like "Headers already sent" or "No such file or directory" must be hidden from a site user as well.
So the problem is more generic now:
How to hide all error messages from a site user
To hide error messages from a site user, you must use a configuration option that is intended exactly for this: display errors. While set to 0 it will prevent PHP from displaying any error occurred. It's best to be set in php.ini but in case you don't have a control over PHP configuration, at least you can set it right in the PHP code:
ini_set('display_errors', 0);
The best part of it, this is just a single place where it's set. So, on your local PC or on a test server you can set it to 1 and watch all errors online. Again, without any changes in the code: as you can see, mysqli already provided a detailed error message, without that if (!$conn) { stuff! But on a live server, display errors must be set to 0, so not a single error message leaks to the user, while log_errors must be set yo 1. That's a simple rule which is, sadly, seldom mentioned in the books or tutorials. By the way, I'd recommend PHP&MySQL book by Jon Duckett, where this approach is explained in detail.
So the only question left is "how to show the user the critical error message?".
How to display a nice error page to a site user
Simply configure an error handler. Here is one from my article on PHP error reporting:
set_exception_handler(function ($e)
{
error_log($e);
http_response_code(500);
if (ini_get('display_errors')) {
echo $e;
} else {
echo "<h1>500 Internal Server Error</h1>
An internal server error has been occurred.<br>
Please try again later.";
}
});
depends on the display_errors value, it will either display the error itself, or just a generic message.
Note that it "gives an HTTP 500 error" which, contrary to your request, is what actually must be done. When your page cannot provide the actual content due to server error, it must respond with 5xx HTTP code.
In local dev environment I see php errors from a call to an external REST service (payment gateway). This is dumped on my browser as expected and shows up in the log console (GAE launcher) - no problem.
Fatal error: Uncaught exception 'Paybrkr\Error\InvalidRequest' with message 'Invalid integer: 997.001' in E:\code\apper\application\libraries\Paybrkr\lib\ApiRequestor.php:98 Stack trace: #0 ...
In production, users just see a blank/500 error which I understand is by design. However the error appears nowhere in the prod logs. I would expect under Critical or Error log level. Any special settings required in php.ini for GAE?
I am using Laravel for a site. I have a page where users can contact me. This sends me an email using the SwiftMailer bundle. It has just been brought to my attention that the following error is seen when trying to send a message
Fatal error: Uncaught exception 'Swift_TransportException'
Exception thrown from here /Applications/MAMP/htdocs/yooies_site/bundles/swiftmailer/library/classes/Swift/Transport/Esmtp/AuthHandler.php on line 176
Code at this location is:
throw new Swift_TransportException(
'Failed to authenticate on SMTP server with username "' .
$this->_username . '" using ' . $count . ' possible authenticators'
);
The cause of the error is not a worry (I found out that I had change my mail password and forgot to change in my sites email config)
The issue I have is that I have Laravel setup to log any exceptions and NOT display them on the main page. I have the following setup in my error.php config file
'detail' => false,
'log' => true,
Why then is my site showing the exception on the page instead of a 500 error?
Full stack trace here (Note I have removed my sites real name and replaced with 'site'
Fatal error: Uncaught exception 'Swift_TransportException'
with message 'Failed to authenticate on SMTP server with username "info+site.com" using 2 possible authenticators'
in /Applications/MAMP/htdocs/site/bundles/swiftmailer/library/classes/Swift/Transport/Esmtp/AuthHandler.php:176
Stack trace:
#0 /Applications/MAMP/htdocs/site/bundles/swiftmailer/library/classes/Swift/Transport/EsmtpTransport.php(307): Swift_Transport_Esmtp_AuthHandler->afterEhlo(Object(Swift_SmtpTransport))
#1 /Applications/MAMP/htdocs/site/bundles/swiftmailer/library/classes/Swift/Transport/AbstractSmtpTransport.php(124): Swift_Transport_EsmtpTransport->_doHeloCommand()
#2 /Applications/MAMP/htdocs/site/bundles/swiftmailer/library/classes/Swift/Mailer.php(79): Swift_Transport_AbstractSmtpTransport->start()
#3 /Applications/MAMP/htdocs/site/application/libraries/personal/mailer.php(55): Swift_Mailer->send(Object(Swift_Message))
#4 /Applications/MAMP/htdocs/site/application/config/error.php(91): Personal\Mai in /Applications/MAMP/htdocs/site/bundles/swiftmailer/library/classes/Swift/Transport/Esmtp/AuthHandler.php on line 176
Laravel version is L3.
Bundle URL here http://bundles.laravel.com/bundle/swiftmailer
Swiftmailer doesn't touch any configuration that's responsible for showing errors. Among the recommendations for production servers is to have display_errors = Off and display_startup_errors = Off, which can be set in php.ini, httpd.conf, .htaccess, .user.ini, etc, or even using ini_set(). You should make sure these directives are correctly set.
I'm not familiar with how Laravel handles exceptions and errors, but it looks like the Swift_TransportException is thrown outside of Laravel's error-handling process. Can you point out where in the flow of the application the exception is thrown? Maybe a stack-trace?
PS: Just a tip: Things like sending emails are better not done during a request at all. You could offload it to some sort of queue, and have another process on the server handle it. You could take a look at Gearman for this.
update
Looking at the stack-trace, it seems Laravel does catch the exception because Log::exception(); is invoked (in application/config/error.php line 91). But the trace doesn't reveal how it got there. Maybe you can run it on a development machine where you have Xdebug installed. Xdebug will give you a more precise stack-trace when the exception is throws, ending with public/index.php (where the request started).
I have a too many hosts PDO exception in my MySQL database:
exception 'PDOException' with message 'SQLSTATE[HY000] [1129] Host
'[IP ADDRESS]' is blocked because of many connection errors; unblock
with 'mysqladmin flush-hosts'' in /var/www/libs/Database.php:15
I understand this error, but the real problem is in the stack trace which dumps the database name, login and password into the console:
Stack trace:
#0 /var/www/libs/Database.php(15): PDO->__construct('mysql:host=conf...',
'[db name]', '[db password]...', Array)
As this is an AJAX request, it dumps into the console browser, which is obviously a problem.
How can I avoid this happening? Have I configured PHP incorrectly?
As this is an AJAX request, it dumps into the console browser
Of course, PHP (like other server-side languages) is executed in another computer and does not have access to your browser's console. Most likely, neither your PHP nor your JavaScript are designed to handle error conditions gracefully. Some tips:
Always set display_errors to false in your production box. Make sure that error messages are logged instead.
Tweak your server-side code so it generates valid output even when the DB is down. For instance, if the script is supposed to generate JSON it should send JSON data even on error. To do so:
Capture the PDOException
Log the error details
Send JSON data informing that there was an error, e.g.:
{"status": "error", "info": "Database is down"}
Tweak your client-side code to handle any kind of error in the AJAX response, including proper JSON with status=error and lack of proper JSON.
I'm having PHP + MySQL code base. If MySQL is stopped and during log-in it fails like this:
Fatal error: Uncaught exception 'FrameworkException' with message 'Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)' in /var/www/html/classes/class.connection.php:24
Stack trace: #0 /var/www/html/login.php(15): Connection::getInstance('localhost', 'user', '__password', 'DB') #1 /var/www/html/login.php(73): isDataValid('lakshmipathi.g#...', 'test') #2 {main} thrown in /var/www/html/classes/class.connection.php on line 24
How to avoid this stack trace? I want to avoid the username and password displayed like this in case of errors
On a production server you should hide the error with the display_errors directive of your php.ini
The error still be logged but not displayed to the end user.
Turning off the error with error_reporting is not a good idea if you need to debug
Nevertheless you should handle the exception :
try {
//Here the code which can throw an exception
} catch(FrameworkException e) {
echo 'an exception occured';
}
I'd recommend using #mysql_connect (or # + whatever function you call) to suppress any error messages. And manually spit out some error. Since you are using some kind of mysterious framework, you could simply catch the exception.
But, for live environments, you should disable any kind error reporting to the user anyway.