About the Author

Chris Shiflett

Chris Shiflett is an author and speaker who leads the web application security practice at OmniTI.


Zend Framework Update

A few weeks ago, I posted my Zend Framework Wishlist. Most of the things I mentioned were off the top of my head, but I think it got people (including me) thinking about how we can make some security problems easier to solve. It also attracted the attention of Open Enterprise Trends, who interviewed me and published a story about the framework. Although it's a bit hard to tell from reading the story, I was interviewed prior to being involved.

I just signed the CLA (Contributor License Agreement) today, so now Brain Bulb is officially part of the project. I'm going to be putting a lot more thought into the topics I brought up in my wishlist, and I hope to make some positive contributions to the project and to PHP.

As you can tell from the listing in Wez's blog, there is an input filtering class called ZInputFilter. Although this is quite nice, trying to address some problems at the input stage is clumsy at best. (If you need an example, look no further than magic_quotes_gpc.) Most problems such as cross-site scripting (XSS) and SQL injection are output problems - once data enters a new context, everything changes (obvious, right?).

Security expert Nitesh Dhanjani correctly notes that a lack of output escaping causes XSS vulnerabilities. (He also notes that the most common mistake it to consider it an input filtering problem.) In the comments that follow his post, examples are provided to illustrate how various languages and platforms handle this particular problem. None of them are too bad, but I'm just not impressed. There must be a better solution.

When developing PHP applications, most of our work involves dealing with strings. When preparing content to be displayed in a browser, we sometimes add markup to those strings:

<?php 

$first_name 
'Chris';
$last_name 'Shiflett';
$city 'New York';
$state 'NY';

$name "<b>$first_name $last_name</b>";
$location "<i>$city, $state</i>";

echo 
"<p>My name is $name, and I live in $location.</p>";

?>

This simple example demonstrates how easy it is to mix dynamic and static data, and the following figure illustrates this further:

The problem is how to make it easy for a developer to guarantee that $first_name, $last_name, $city, and $state are going to be treated as raw data. They need to be escaped with htmlentities() (or htmlspecialchars()), but $name and $location are clearly meant to contain markup, so escaping them would not be desirable. In other words, we often create strings in PHP that contain disparate types of data, and problems can arise when it is not properly handled. Currently, a developer's only defense is knowledge and discipline, but I think we can do better.

When sending data to a database, this problem has already been solved. Bound parameters guarantee that raw data never enters a context where it can be considered anything but data:

<?php 

$db 
= new mysqli('localhost''user''pass''database');
$query $db->prepare('SELECT *
                       FROM   users
                       WHERE  username = ?
                       AND    password = ?'
);
$query->bind_param('ss'$username$password);
$query->execute();

?>

(This isn't meant to teach you how to use bound parameters. For more information, see Zak Greant and Georg Richter's article on ext/mysqli or the "Prepared Statements" section of Wez Furlong's article on PDO.)

This example demonstrates how a developer can indicate which parts of a string are meant to be raw data ($username and $password in this case) and which parts are meant to be interpreted (the SQL statement). It is this separation that is key.

I think this solution works well, because interacting with a database isn't much easier without the use of bound parameters. Sending data to the client is as easy as using echo, so any solution to the XSS problem can't be too cumbersome. However, the developer must indicate the distinction between these disparate types of data, so some overhead in terms of syntax is unavoidable.

I'll post more once I've had a few beers. :-) I welcome your comments and suggestions.

About This Post

Zend Framework Update was posted on Sat, 12 Nov 2005 at 02:30:33 GMT.

9 Comments

1. Chris Snyder's GravatarChris Snyder said:

One really important addition to the framework, and you're going to laugh at this because it sounds so simple, might be a handy wrapper for Unicode-friendly, XSS-denying htmlentities( $string, ENT_QUOTES, 'utf-8' ). Perhaps something like h8( $string ). Does the fix really need to be any more complicated than this?

The other thing that would help a lot is a function to strip control characters, optionally leaving newline and tab in place. I think strip_control_chars( string $input, [optional] string $ignore ) would be valuable in a number of contexts, from email to HTTP headers to data passed to other processes.

Sat, 12 Nov 2005 at 15:33:28 GMT Link


2. Ben Ramsey's GravatarBen Ramsey said:

Templating engines often catch a lot of flack and are sometimes at the center of great debates in the community. Some love them. Some hate them. But there is one good thing about them in this respect: some of them use methods akin to bound parameters, and perhaps this is the solution. Allowing developers to bind parameters to a template -- in much the same way that we bind parameters to an SQL statement -- will ensure that the raw data is properly escaped when the entire document is sent to the client. This could work for any kind of template for output, not just HTML.

Still any developer could shoot themselves in the foot by simply echoing raw data, but, then, any developer could also send raw data to a database without using bound parameters, but introducing some kind of mechanism for bound paramters for use with any kind of output would definitely help people get into the habit. And maybe this could be a PECL extension so that it's built into the language and works fast.

Sun, 13 Nov 2005 at 01:51:23 GMT Link


3. Trevor's GravatarTrevor said:

I was wondering why you're working with the Zend framework instead of something like, say, Cake. I don't know anything at all about either (in fact, I've never used a framework at all!) and I'm curious to hear what it is that appeals to you about the Zend framework over others. Is it the high profile of Zend? The corporate interest in it?

Mon, 14 Nov 2005 at 04:09:01 GMT Link


4. Chris Shiflett's GravatarChris Shiflett said:

Hi Trevor,

I never really intended to choose between frameworks. When Zend asked me to help out, I was choosing between yes and no, not between Zend and Cake (or any other framework).

I'll admit that I would probably have politely refused if I didn't think many people would use the framework. I don't have a lot of free time, so I want to help as many people as I can with my contributions. I think the Zend Framework is going to be a useful tool for everyone.

Mon, 14 Nov 2005 at 05:42:37 GMT Link


5. Richard Lynch's GravatarRichard Lynch said:

For those of us who hate templating systems (other than PHP itself)...

The bound parameters solution reminds me of sprintf() for output.

Perhaps some kind of function like sprintf() that treats the first arg as static/safe text, and the remainder as data to be escaped would be good...

You'd still need the discipline to know that this is fine:

$name = safe_print('%s %s', $first_name, $last_name);

$output = safe_print("<p>Hello $name from %s", $location);

echo $output;

This could, perhaps, involve a default function of 'htmlentities' but which could be set to something else with, say:

function htmlentities8 ($data){

return htmlentities($data, ENT_QUOTES, 'UTF-8');

}

safe_print_handler('htmlentities8');

Or maybe the default should be the equivalent of htmlentities8 above -- I'm more concerned that we as a community do something to induce better habits throughout the community, and that it's SIMPLE and PORTABLE enough that it gets into every PHP compilation.

I shouldn't have to install/configure anything "extra" to use fundamental Security principles.

An alarm system may not come with a house you buy, or an apartment you rent, but you pretty much expect a simple dead-bolt, no?

I'm pretty sure it's a law in some communities that an apartment has to have a working dead-bolt.

Surely our base solution for minimal Security should be a fundamental part of the PHP language, not some add-on second thought.

This is not intended as derogatory towards PECL or any other extension system (PEAR, etc)

But I think Security is too important to relegate the basics to anything less than PHP core.

Extended alarm systems and captcha and whatnot, sure.

But input and output filtering?

Core.

jmho

Mon, 14 Nov 2005 at 20:52:14 GMT Link


6. Ben Ramsey's GravatarBen Ramsey said:

Richard:

I noticed today that sniper made check-ins to pecl/filter with the log note: "- Prepare for including in PHP core." I'm not sure exactly what the plan is, but this sounds like a move in the direction you're talking about.

Wed, 16 Nov 2005 at 01:56:47 GMT Link


7. Alin's GravatarAlin said:

Hi Chris,

You said you signed the CLA, does contributing to Zend Framework is based on an invitation only?

How can I contribute to this framework?

Thanks.

Wed, 30 Nov 2005 at 14:04:03 GMT Link


8. Chris Shiflett's GravatarChris Shiflett said:

Hi Alin,

Yes, I think you have to be invited to contribute. I'm not sure what their current and future organizational plans are, because I'm just a contributor. However, I do know that the framework is being designed to be easy to extend, so there's always the opportunity to write your own components.

Fri, 02 Dec 2005 at 21:32:04 GMT Link


9. Chris Shiflett's GravatarChris Shiflett said:

A better answer is provided here:

http://zend.com/collaboration/qanda.php

"We're now working on setting up the collaboration infrastructure and engagement guidelines. We expect to have them ready by January 2006."

Fri, 02 Dec 2005 at 22:11:53 GMT Link


Post A Comment

Personal Details and Comment

Style Guide

Line breaks are converted to paragraphs. Also use:

  • <a href="" title="">text</a>1
  • <em>text</em>
  • <blockquote><p>text</p></blockquote>
  • <code>2  <?php  if ($foo) {      $foo = TRUE;  }  ?></code>
  1. Note: <code> can be used inline (e.g. in paragraphs) or in a block as shown. Include whitespace and newlines in blocks.

Please enter Chris (my first name) below. This is a primitive spam prevention technique, and I apologize for the inconvenience.

Preview and Submit

Upcoming Talks

php|works / PyWorks

12 - 14 Nov 2008

At Sheraton Gateway Hotel Atlanta Airport, Atlanta, Georgia.

New Comments

Dave wrote:

Hi Seth, I'm experiencing exactly the same problem as you have. Have you fixed it? How?

Posted in
Matt Robinson wrote:

Wotcha Chris, thanks for the tip about headers in the web inspector, I hadn't noticed them! (Actu...

Posted in Inspecting and Hacking HTTP
Stelian Mocanita wrote:

Not much I know so far, didn't get far with debugging it to get as far as http headers but I know...

Posted in Facebook Worm
Chris Shiflett wrote:

Yes, good point. The message this worm sends is really just a phishing attack, and Facebook is do...

Posted in Facebook Worm
yawnmoth wrote:

Given that Samy required no action on the users part, above and beyond viewing an infected users ...

Posted in Facebook Worm

Browse Comments