SQL Injection Vulnerabilities
SQL injection vulnerabilities are yet another class of input validation flaws. Specifically, they allow for the exploitation of a database query. For example, in your PHP script, you might ask the user for a user ID and password, then check for the user by passing the database a query and checking the result.
SELECT * FROM users WHERE name='$username' AND pass='$password';
However, if the user who’s logging in is devious, he may enter the following as his password:
' OR '1'='1
This results in the query being sent to the database as:
SELECT * FROM users WHERE name='known_user' AND pass='' OR '1'='1';
This will return the username without validating the password — the malicious user has gained entry to your application as a user of his choice. To alleviate this problem, you need to escape dangerous characters from the user-submitted values, most particularly the single quotes (‘). The simplest way to do this is to use PHP’s
$username = addslashes($_POST["username"]);
$password = addslashes($_POST["password"]);
But depending on your PHP configuration, this may not be necessary! PHP’s much-reviled magic quotes feature is enabled by default in current versions of PHP. This feature, which can be disabled by setting the
php.ini variable to
Off, will automatically apply
addslashes to all values submitted via GET, POST or cookies. This feature safeguards against inexperienced developers who might otherwise leave security holes like the one described above, but it has an unfortunate impact on performance when input values do not need to be escaped for use in database queries. Thus, most experienced developers elect to switch this feature off.
If you’re developing software that may be installed on shared servers where you might not be able to change the
php.ini file, use code to check that status of
magic_quotes_gpc and, if it is turned on, pass all input values through PHP’s
stripslashes() function. You can then apply
addslashes() to any values destined for use in database queries as you would normally.
$_GET = array_map('stripslashes', $_GET);
$_POST = array_map('stripslashes', $_POST);
$_COOKIE = array_map('stripslashes', $_COOKIE);
SQL injection flaws do not always lead to privilege escalation. For instance, they can allow a malicious user to output selected database records if the result of the query is printed to your HTML output.
You should always check user-provided data that will be used in a query for the characters
'",;() and, possibly, for the keywords
"WHERE" in a case-insensitive fashion. These are the characters and keywords that are useful in a SQL insertion attack, so if you strip them from user inputs in which they’re unnecessary, you’ll have much less to worry about from this type of flaw.
You should ensure that your
display_errors php.ini value is set to "0". Otherwise, any errors that are encountered in your code, such as database connection errors, will be output to the end user’s browser. A malicious user could leverage this flaw to gain information about the internal workings of your application, simply by providing bad input and reading the error messages that result.
display_errors value can be set at runtime using the
ini_set function, but this is not as desirable as setting it in the ini file, since a fatal compilation error of your script will still be displayed: if the script has a fatal error and cannot run, the
ini_set function is not run.
Instead of displaying errors, set the
error_log ini variable to "1" and check your PHP error log frequently for caught errors. Alternatively, you can develop your own error handling functions that are automatically invoked when PHP encounters an error, and can email you or execute other PHP code of your choice. This is a wise precaution to take, as you will be notified of an error and have it fixed possibly before malicious users even know the problem exists. Read the PHP manual pages on error handling and learn about the
Data Handling Errors
Data handling errors aren’t specific to PHP per se, but PHP application developers still need to be aware of them. This class of error arises when data is handled in an insecure manner, which makes it available to possible interception or modification by malicious parties.
The most common type of data handling error is in the unencrypted HTTP transmission of sensitive data that should be transmitted via HTTPS. Credit card numbers and customer information are the most common types of secured data, but if you transmit usernames and passwords over a regular HTTP connection, and those usernames and passwords allow access to sensitive material, you might as well transmit the sensitive material itself over an unencrypted connection. Use SSL security whenever you transmit sensitive data from your application to a user’s browser. Otherwise, a malicious eavesdropper on any router between your server and the end user can very easily sniff the sensitive information out of the network packets.
The same type of risk can occur when applications are updated using FTP, which is an insecure protocol. Transferring a PHP file that contains database passwords to your remote Webserver over an insecure protocol like FTP can allow an eavesdropper to sniff the packets and reveal your password. Always use a secure protocol like SFTP or SCP to transmit sensitive files. Never allow sensitive information to be sent by your application via email, either. An email message is readable by anyone who’s capable of reading the network traffic. A good rule of thumb is that if you wouldn’t write the information on the back of a postcard and put it through the mail, you shouldn’t send it via email, either. The chance anyone will actually intercept the message may be low, but why risk it?
It’s important to minimize your exposure to data handling flaws. For example, if your application is an online store, is it necessary to save the credit card numbers attached to orders that are more than six months old? Archive the data and store it offline, limiting the amount of data that can be compromised if your Webserver is breached. It’s basic security practice not only to attempt to prevent an intrusion or compromise, but also to mitigate the negative effects of a successful compromise. No security system is ever perfect, so don’t assume that yours is. Take steps to minimize the fallout if you do suffer a penetration.
Configuring PHP For Security
Generally, most new PHP installations that use recent PHP releases are configured with much stronger security defaults than was standard in past PHP releases. However, your application may be installed on a legacy server that has had its version of PHP upgraded, but not the php.ini file. In this case, the default settings may not be as secure as the default settings on a fresh install.
You should create a page that calls the
phpinfo() function to list your php.ini variables and scan them for insecure settings. Keep this page in a restricted place and do not allow public access to it. The output of
phpinfo() contains information that a potential hacker might find extremely useful.
Some settings to consider when configuring PHP for security include:
register_globals: The boogeyman of PHP security is
register_globals, which used to default to "on" in older releases of PHP but has since been changed to default to "off". It exports all user input as global variables. Check this setting and disable it — no buts, no exceptions. Just do it! This setting is possibly responsible for more PHP security flaws than any other single cause. If you’re on a shared host, and they won’t let you disable
register_globals, get a new host!
safe_mode: The safe mode setting can be very useful to prevent unauthorized access to local system files. It works by only allowing the reading of files that are owned by the user account that owns the executing PHP script. If your application opens local files often, consider enabling this setting.
disable_functions: This setting can only be set in your php.ini file, not at runtime. It can be set to a list of functions that you would like disabled in your PHP installation. It can help prevent the possible execution of harmful PHP code. Some functions that are useful to disable if you do not use them are system and exec, which allow the execution of external programs.
Read the security section of the PHP manual and get to know it well. Treat it as material for a test you’ll take and get to know it backwards and forwards. You will be tested on the material by the hackers who will indubitably attempt to penetrate your site. You get a passing grade on the test if the hackers give up and move on to an easier target whose grasp of these concepts is insufficient.
The following sites are recommended reading to maintain your security knowledge. New flaws and new forms of exploits are discovered all the time, so you cannot afford to rest on your laurels and assume you have all the bases covered. As I stated in the introduction to this article, "Security is a process", but security education is also a process, and your knowledge must be maintained.
OWASP, The Open Web Application Security Project, is a non-profit oganisation dedicated to "finding and fighting the causes of insecure software". The resources it provides are invaluable and the group has many local chapters that hold regular meetings with seminars and roundtable discussions. Highly recommended.
CGISecurity.Net is another good site dealing with Web application security. They have some interesting FAQs and more in-depth documentation on some of the types of flaws I’ve discussed in this article.
The security section of the PHP Manual is a key resource that I mentioned above, but I include it here again, since it’s full of great information that’s directly applicable to PHP. Don’t gloss over the comments at the bottom of each page: some of the best and most up-to-date information can be found in the user-contributed notes.
The PHP Security Consortium offers a library with links to other helpful resources, PHP-specific summaries of the SecurityFocus newsletters, the PHP Security Guide, and a couple of articles.
The BugTraq mailing list is a great source of security related advisories that you should read if you’re interested in security in general. You may be shocked by the number of advisories that involve popular PHP applications allowing SQL insertion, Cross Site Scripting and some of the other flaws I’ve discussed here.
Linux Security is another good site that is not necessarily restricted to PHP but, since you are likely running a Linux Webserver to host your PHP applications, it’s useful to try to stay up to date on the latest advisories and news related to your chosen Linux distribution. Don’t assume your hosting company is on top of these developments; be aware on your own — your security is only as good as your weakest point. It does you no good to have a tightly secured PHP application running on a server with an outdated service that exposes a well-known and exploitable flaw.
As I’ve shown in this article, there are many things to be aware of when programming secure PHP applications, though this is true with any language, and any server platform. PHP is no less secure than many other common development languages. The most important thing is to develop a proper security mindset and to know your tools well. I hope you enjoyed this article and learned something as well! Remember: just because you’re paranoid doesn’t mean there’s no one out to get you.
If you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like PHP & MySQL Web Development for Beginners.