![]() | ![]() | ![]() | ||||||||
![]() | ||||||||||
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 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 CIn 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 engineThe 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 objectsThe 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 ManagementQuercus 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 implementationQuercus 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. Any significant PHP program will use 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 visibilityOften, 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 visibilityMany 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. register_globalsQuercus 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. 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']); ?>
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 filesBecause 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 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
Database Injection ProtectionIn 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 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); Configuration files and passwordsPHP 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> URL-based sessionsWe 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 HijackingNormal 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. 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>
|