Caucho Technology
documentation
examples
changes

overview
quick start
installation
command-line
configuration
admin
amber
clustering
caching
database
deployment
ejb 3.0
embedding
filters
hessian
hmtp
ioc
jsp
logging
messaging
performance
quercus/php
remoting
scheduled tasks
security
server push
servlets
third-party
troubleshooting
virtual hosting
watchdog
webapp
xml and xslt

security
module status

quercus security


Description of Quercus and PHP Security Issues

C language vulnerabilities

Since Quercus implements PHP in the Java language as opposed to C, it is automatically protected from a number of C-language security issues. The most important issue is buffer and pointer overruns, but also includes memory issues.

Buffer Overruns in C

In the C language, strings, arrays, and objects are all referenced by pointers. The simplest example of a security issue is the buffer overflow. The following example has a string of length 10, but the code changes a value at location 20. In Java, the equivalent code would raise an exception. In C, this code writes data at the location 20, even though it is beyond the end of the code and is almost certainly pointing to other important information.

example buffer overrun
void
foo()
{
  char data[10];

  data[20] = '!';
}

At best, this kind of error will cause a segmentation-violation and force the program to exit, at worst it can create mini-programs which an attacker can use to gain control of the web server.

The issue in a C program like PHP is that every single pointer reference must be correct and checked for overruns by the application code. If the programmers miss a single instance, a hacker could use that bug to run malicious code on the web server.

The issue does not apply just to arrays, but to all objects, strings, and pointers, since all objects can be cast to a string and that pointer can be used to modify any memory.

In a Java program like Quercus, this isn't an issue because Java itself protects every array or object reference. Java will catch any application pointer bug or buffer overflow and throw an exception. Java code can't create and execute mini-programs like C-code can.

PHP language engine

The first potential source of C-related bugs in PHP is in the language implementation itself. A language implementation consists of a parser, an interpreter/compiler, and runtime objects like strings, arrays, database connections, etc.

Quercus can run PHP in either interpreted or compiled modes. In the interpreted mode, Quercus executes the parsed program directly. In the compiled mode, Quercus compiles the PHP code to Java code and then executes Java code. In both cases, the underlying execution uses the Java virtual machine and Java's just-in-time compiler for performance. Quercus's execution engine is protected by Java's implementation and the JDK is very solid and safe technology.

In contrast, PHP implements its own bytecode interpreter in C. This means a bug in the PHP bytecode interpreter could result in a pointer security problem, where that issue is absent from Quercus's implementation.

PHP runtime objects

The basic runtime objects for PHP need to be implemented as well, the strings, arrays, objects, etc. Quercus implements these objects as Java objects directly. PHP implements these objects as C objects. The same issues that arise for the interpreter arise for the objects. A pointer failure or failure to initialize data in a PHP array could cause security problems in the C implementation, while an identical bug in Quercus would merely throw an exception.

Memory Management

Quercus automatically uses Java's memory management and garbage collection system. This means any unused object can simply be dropped and the garbage collector will automatically reuse the object at next GC time. The garbage collector simplifies the Quercus module code (less code is less potential bugs) and makes certain kinds of memory leaks impossible.

The C implementation of PHP needs to implement its own memory management, using a reference counting system. This means any library code needs to explicitly dereference an object when it's done using it. Forgetting to do so creates a new bug.

Library/Module implementation

Quercus libraries and modules are written in Java. PHP libraries are written in C. This implementation language choice means any extension library for PHP is subject to the same security issues as described above. Not only does every aspect of the PHP language and objects need to be correct, but all the libraries and modules need to be correct.

In contrast, Quercus libraries are just Java programs. Any Quercus extension is automatically protected by the Java language. So a site can confidently download a Quercus module from a site like sourceforge and be confident that it doesn't introduce an additional C-language security bug.

PHP include visibility

Any significant PHP program will use include to structure the code, executing code from another PHP file. The included files are valid PHP programs, but are not meant to be browsed. However, since the included files are valid PHP programs they will be browsed and executed if a browser points to the program.

Most PHP programs protect themselves by adding some extra code to the top of every included file to check if they're being used properly:

inc.php example protection
<php?

if (! $check_include)
  die("illegal include file");

...
?>

The include-protection code works, but does require the PHP programmer to be careful about each included files. Any mistake can cause an unexpected file to be executed.

Quercus programmers can instead put all their included files in the WEB-INF directory, e.g. in WEB-INF/php. Any Java application server will automatically protects all files in WEB-INF directory from all browsing. So the PHP include of WEB-INF/php/inc.php will execute the included files, but that file is not browable by an external user.

Configuration file visibility

Often, PHP configuration will be written in PHP itself. This scripting configuration makes customizing PHP programs very simple and accessible without needing to learn a new syntax, but runs into the same potential PHP include vulnerability listed above. In Quercus, configuration files belong in the WEB-INF directory where they are protected from malicious spying.

Temporary and data file visibility

Many applications need to create temporary file or store plain data files. Java applications are accustomed to using either WEB-INF as their default data directory or configure an external temporary location. Because WEB-INF is protected, any temporary file is protected as well.

PHP language issues

register_globals

Quercus does not implement the deprecated register_globals capability of PHP. So it is impossible for a misconfiguration to open that particular vulnerability.

register_globals is a deprecated feature (disabled by default in PHP), which automatically registered a form's data as PHP variables. So the register_globals feature opened a large security hole where an attacker could post a bogus form with non-sensical variables to confuse or reconfigure the script.

Cross site scripting (XSS)

Since cross-side scripting attacks prey on application errors, not the language engine, both Quercus and PHP programs must take care to filter their input. See http://en.wikipedia.org/wiki/Cross_site_scripting.

The basic cross-site scripting vulnerability occurs when an application trusts form data and redisplays it to a user. For example, a buggy bulletin board system might display a comment without escaping the HTML. Since HTML can include JavaScript, this could allow a malicious commenter to leave some HTML which executed JavaScript on a browser, e.g.

<script language="javascript">alert("This is a bogus alert");</script>

The PHP libraries provide a number of functions to help protect against cross-site scripting attacks. A simple example might be:

<?php

$clean['message'] = htmlentities($_GET['message']);

?>
  • htmlentities()
  • htmlspecialchars()
  • strtr()
  • strip_tags()
  • utf8_decode()

URLs and Forms

URL and form POST data can be easily spoofed; it does not take a sophisticated hacker to generate any HTTP input. So any script that takes data from the internet must validate the GET, header and POST data before acting on it.

The dangers of this issue is apparent to anyone who looks at web server logs and finds many examples of bogus URLs for programs not even installed on the server.

URLs and files

Because PHP can create strings so easily, it's temping to build an application which selects a file based on the URL data, e.g. for a URL http://foo.com/index.php?page=submit.php.

Bogus index.php
<?php

include ("page/{$_GET['page']}");

?>

Because that example does no validation, any PHP script on the server at all could be displayed. A better solution would be:

Better index.php
<?php

$commands = array("comment" => "comment.php",
                  "display" => "display.php");

$clean_page = $commands[$_GET['page']];

if (! $clean_page)
  die();

eval(), system(), and passthru()

Any command which interprets string as PHP or executes a system command is especially dangerous. Consider:

bogus.php
<?php

eval($_GET['data']);

If the URL was http://foo.com/bogus.php?data=passthru("cat /etc/passwd"), you'd have exposed the server's passwords.

  • addslashes()
  • escapeshellarg()
  • escapeshellcmd()
  • realpath()

Database Injection Protection

In general, web data cannot be trusted. This is especially true for data that modifies the database. The standard bad example is:

php database injection
<?php

$sql = "INSERT INTO test VALUES ('{$_POST['data']}')";

?>

With the previous bogus code, an attacker could add two records with the following data:

first'), ('second

To protect against this, you can use the newer PDO interface to avoid the issue entirely, or use escaping functions like mysql_escape_string(). The PDO interface has two advantages: it works for all databases, and it's less likely to forget to escape the data. The PDO code might looks like:

PDO bindValue INSERT code
<?php

$pdo = new PDO("java:comp/env/jdbc/test");

$sql = "INSERT INTO test VALUES(?)";

$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, $_POST['data']);
$stmt->execute();

The older mysql-style escaping also exists, but newer code should migrate to PDO:

PDO bindValue INSERT code
<?php

$clean_data = mysql_escape_string($_POST['data']);

$sql = "INSERT INTO test VALUES($clean_data)";

mysql_query($sql);

Database Security issues

Configuration files and passwords

PHP programs often configure the databases inside the PHP code itself or in included files. As mentioned above, Quercus can make the confguration more secure from prying eyes by putting the configuration into the WEB-INF directory.

In addition, Quercus can use Java DataSources directly, taking the configuration out of the PHP code entirely. This configuration will take precedence over the PHP code, so you can secure an existing application without any changes. The Quercus configuration looks like:

WEB-INF/resin-web.xml configuration of Java database
<web-app xmlns="http://caucho.com/ns/resin">

  <database jndi-name="jdbc/test">
    <driver type="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"
     <url>jdbc:mysql://localhost:3306/test</url>
     <user>foo</user>
     <password>bar</password>
   </driver>
  </database>

  <servlet-mapping url-pattern="*.php"
                   servlet-class="com.caucho.quercus.servlet.QuercusServlet">
    <init>
      <database>jdbc/test</database>
    </init>
  </servlet-mapping>
</web-app>

Session Security

URL-based sessions

We strongly discourage the use of URL-based sessions as a serious security risk. By default, Quercus disables URL-based sessions. URL-based sessions are particular problems because users will blindly cut and paste URLs with their session information and post them in public places. Because these kinds of security breaches occur by simple mistakes and not concerted hacker attempts, they are far more common and serious.

The URL-based sessions in PHP look something like:

http://foo.com/test.php?PHPSESSID=asdf

Cookie Hijacking

Normal HTTP requests are sent in cleartext across the internet, including the cookie values which keep track of sessions. Because the data is in the clear, it's possible for a malicious hacker to look at the HTTP request, copy the cookie, and forward a new request to a web site. For this reason, you should use SSL for any session that passes any sort of important data, and also timeout any sessions which carry important information.

Extra information

By default, PHP sends error messages to the browser. On a production system, this should be turned off:

<web-app xmlns="http://caucho.com/ns/resin">

  <servlet-mapping url-pattern="*.php"
                    servlet-class="com.caucho.quercus.QuercusServlet">
    <init>
      <php-ini display_errors="Off" log_errors="On"/>
    </init>
  </servlet-mapping>

</web-app>

Copyright © 1998-2008 Caucho Technology, Inc. All rights reserved.
Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.