What Goes in Your Code

Many of the code snippets we have shown for accessing databases have included the database name, username, and user password in plain text, as follows:

$conn = @new mysqli("localhost", "bob", "secret", "somedb");

While this is convenient, it is slightly insecure because somebody could have immediate access to our database with the full permissions that the user "bob" has if he got his hands on our .php file.

It would be better to put the username and password in a file that is not in the document root of the web application and include it in our script, as follows:





We should think about doing the same thing for other sensitive data.

Some would argue that any file not directly accessible to the user from the Internet should not find a place in the document root of the web site. For example, if the document root for our message board web site is /home/httpd/messageboard/www, we should place all of our .inc files and other files in a place such as /home/httpd/messageboard/code. When we want to include those files, we can simply write in our code:

require_once('../code/user_object.inc');

The reasons for this degree of caution come down to what happens when a malicious user makes a request for a file that is not a .php or .html file. Many web servers default to dumping the contents of that file to the output stream. Thus, if we were to keep user_object.inc in the public document root and the user requested it, he might see a full dump of our code in his web browser. This would let him see the implementation, get at any intellectual property we might have in this file, and potentially find exploits that we might have missed.

To fix this, we should be sure that the web server is configured to only allow the request of .php and .html files , and that requests for other types of files should return an error from the server.

Similarly, files such as password files, text files, configuration files, or special directories are best kept away from the public document root. Even if we think we have our web server configured properly, we might have missed something. Or if our web application is moved to a new server that is not properly configured in the future, we might be exposed to exploitation.

HTML form elements have no types associated with them, and most pass strings (which may represent things such as dates, times, or numbers) to the server. Thus, if you have a numeric field, you cannot assume that it was entered as such. Even in environments where powerful client side code can try to make sure that the value entered is of a particular type, there is no guarantee that the values will not be sent to the server directly, as in the "Double Checking Expected Values" section.

An easy way to make sure that a value is of the expected type is to cast or convert it to that type and use it, as follows:

$number_of_nights = (int)$_POST['num_nights'];

if ($number_of_nights == 0)
{
echo "ERROR: Invalid number of nights for the room!";
exit;
}

If we have the user input a date in a localized format, such as "mm/dd/yy"' for users in the United States, we can then write some code to verify it using the PHP function called checkdate. This function takes a month, day, and year value (4-digit years), and indicates whether or not they form a valid date:

// split is mbcs-safe via mbstring (see chapter 5)

$mmddyy = split($_POST['departure_date'], '/');
if (count($mmddyy) != 3)
{
echo "ERROR: Invalid Date specified!";
exit;
}

// handle years like 02 or 95
if ((int)$mmddyy[2] <> 50)
$mmddyy[2] = (int)$mmddyy[2] + 1900;
else if ((int)$mmddyy[2] >= 0)
$mmddyy[2] = (int)$mmddyy[2] + 2000;

// else it's <>

By taking the time to filter and validate the input, we can not only help ourselves out for natural error-checking that we should be doing in the first place (such as verifying whether a departure date for a plane ticket is a valid date), but we can also improve the security of our system.

top