As the mantra goes, filter input, and escape output.
Believe it or not, escaping in PHP is not terribly easy to get right. For
example, to properly escape HTML, you need to use
htmlspecialchars(), with the
ENT_QUOTES | ENT_SUBSTITUTE, and provide a character encoding. Who
really wants to write
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'utf-8')
every single time they need to escape a string for use in HTML?
zend-escaper only requires PHP (of at least version 5.5 at the time of writing), and is installable via composer:
$ composer require zendframework/zend-escaper
While we considered making zend-escaper act as either functions or static
methods, there was one thing in the way: proper escaping requires knowledge of
the intended output character set. As such,
Zend\Escaper\Escaper must first be
instantiated; once it has, you call methods on it.
use Zend\Escaper\Escaper; $escaper = new Escaper('iso-8859-1');
By default, if no character set is provided, it assumes
utf-8; we recommend
using UTF-8 unless there is a compelling reason not to. As such, in most cases,
you can instantiate it with no arguments:
use Zend\Escaper\Escaper; $escaper = new Escaper();
The class provides five methods:
escapeHtml(string $html) : stringwill escape the string so it may be safely used as HTML. In general, this means
&characters (as well as others) are escaped to prevent injection of unwanted tags and entities.
escapeHtmlAttr(string $value) : stringescapes a string so it may safely be used within an HTML attribute value.
escapeJs(string $js) : stringescapes a string so it may safely be used within a
<script>tag. In particular, this ensures that the code injected cannot contain continuations and escape sequences that lead to XSS vectors.
escapeCss(string $css) : stringescapes a string to use as CSS within
<style>tags; similar to JS, it prevents continuations and escape sequences that can lead to XSS vectors.
escapeUrl(string $urlPart) : stringescapes a string to use within a URL; it should not be used to escape the entire URL itself. It should be used to escape things such as the URL path, query string parameters, and fragment, however.
So, as examples:
echo $escaper->escapeHtml('<script>alert("zf")</script>'); // results in "<script>alert("zf")</script>" echo $escaper->escapeHtmlAttr("<script>alert('zf')</script>"); // results in "<script>alert('zf')</script>" echo $escaper->escapeJs("bar"; alert("zf"); var xss="true"); // results in "bar\x26quot\x3B\x3B\x20alert\x28\x26quot\x3Bzf\x26quot\x3B\x29\x3B\x20var\x20xss\x3D\x26quot\x3Btrue" echo $escaper->escapeCss("background-image: url('/zf.png?</style><script>alert(\'zf\')</script>');"); // results in "background\2D image\3A \20 url\28 \27 \2F zf\2E png\3F \3C \2F style\3E \3C script\3E alert\28 \5C \27 zf\5C \27 \29 \3C \2F script\3E \27 \29 \3B" echo $escaper->escapeUrl('/foo " onmouseover="alert(\'zf\')'); // results in "%2Ffoo%20%22%20onmouseover%3D%22alert%28%27zf%27%29"
As you can see from these examples, the component aggresively filters each string to ensure it is escaped correctly for the context for which it is intended.
How and where might you use this?
The main point is that escaping can be easy with zend-escaper; start securing your output today!
Save the date!
Want to learn more about Expressive and Zend Framework? What better location than ZendCon 2017! ZendCon will be hosted 23-26 October 2017 in Las Vegas, Nevada, USA. Visit the ZendCon website for more information.
Subscribe to this blog via RSS.