Location: PHPKode > scripts > CSP Filter > csp-filter/README.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>CSP Output Filter Class</title>
<script src="testscript.js" type="text/javascript"></script>
<!-- this is here to test filtering of meta after none meta elements in head -->
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
<style type="text/css">
body {
   background-color: #eeeeee;
   }

.mono {
   font-family: Monaco, "Lucida Mono", "Lucida Mono EFOP", "Lucida Mono EF", Courier, monospace;
   color: blue;
   }
   
.red {
   color: red;
   }
   
.green {
   color: green;
   }
  
pre {
   font-family: Monaco, "Lucida Mono", "Lucida Mono EFOP", "Lucida Mono EF", Courier, monospace;
   color: blue;
   }
   
pre.cspreport {
   font-family: Monaco, "Lucida Mono", "Lucida Mono EFOP", "Lucida Mono EF", Courier, monospace;
   color: blue;
   font-size: 0.8em;
   }
  
div.content {
   margin-left: 10%;
   width: 40em;
   float: left;
   }

h1 {
   margin-left: -6%;
   }
  
h2,h3,h4 {
   margin-left: -3%;
   }
  
dt {
   margin-left: -2%;
   font-family: Monaco, "Lucida Mono", "Lucida Mono EFOP", "Lucida Mono EF", Courier, monospace;
   font-weight: bold;
   color: blue;
   }
   
dt.bug {
   margin-left: -2%;
   font-family: Monaco, "Lucida Mono", "Lucida Mono EFOP", "Lucida Mono EF", Courier, monospace;
   font-weight: normal;
   color: red;
   }
  
dd {
   margin-left: 2%;
   }
  
#pagenav {
   width:100%;
   height:30px;
   background: #DDCCEE;
   font-variant: small-caps;
   }

#pagenav ul {
   margin:0px; padding:0px;
   }

#pagenav ul li {
   display:inline;
   float:left;
   list-style:none;
   margin-left:15px;
   margin-top: 5px;
   position:relative;
   height:30px;
   }

#pagenav li a {
   color: #7B68EE;
   text-decoration:none;
   }

#pagenav li a:hover {
   color: #C00;
	background: #FC0;
   text-decoration:none;
   }

#pagenav li ul {
   margin:0px;
   padding:0px;
   display:none;
   position:absolute;
   left:0px;
   top:20px;
   background-color:#999;
   }

#pagenav li:hover ul {
   display:block;
   width:170px;
   }
   
#pagenav li:hover ul.impl {
   display:block;
   width:220px;
   }
   
#pagenav li:hover ul.usage {
   display:block;
   width:180px;
   }

#pagenav li li {
   list-style:none;
   display:list-item;
   }

#pagenav li li a {
   color:#fff;
   text-decoration:none;
   }

#pagenav li li a:hover {
   color:#fff;
   text-decoration:underline;
   }
</style>
</head>
<body onload="parReplace();">
<div id="pagenav">
<ul>
<li><a href="#CSP">CSP</a></li>
<li><a href="#sscsp">Server Side CSP</a>
  <ul>
  <li><a href="#source">Class Source</a></li>
  <li><a href="#target">Target Audience</a></li>
  <li><a href="#license">License</a></li>
  </ul></li>
<li><a href="#implement">CSP Implementation</a>
  <ul class="impl">
  <li><a href="#cspimage">Image Nodes</a></li>
  <li><a href="#cspmedia">Media Nodes</a></li>
  <li><a href="#cspscript">Script Nodes</a></li>
  <li><a href="#cspobject">Object Nodes</a></li>
  <li><a href="#cspframe">Frame Nodes</a></li>
  <li><a href="#cspstyle">Style Sheets</a></li>
  <li><a href="#report">Trigger Notification</a></li>
  </ul></li>
<li><a href="#beyondcsp">Beyond CSP</a>
  <ul>
  <li><a href="#whitelist">Event Whitelist</a></li>
  <li><a href="#scriptinhead">Script In Head</a></li>
  <li><a href="#otherchecks">Other Checks</a></li>
  </ul></li>
<li><a href="#demo">Live Testing</a></li>
<li><a href="#Coleoptera">Known Bugs</a>
  <ul>
  <li><a href="#checkme">Needs Checking</a></li>
  <li><a href="#checkme">Spec Questions</a></li>
  </ul></li>
<li><a href="#usage">Class Usage</a>
  <ul class="usage">
  <li><a href="#notInput">Not Input Filter</a></li>
  <li><a href="#completeDocument">Full Document</a></li>
  <li><a href="#php5">PHP 5 Only</a></li>
  <li><a href="#tidy">Tidy Gotcha</a></li>
  <li><a href="#idna">IDNA Hosts</a></li>
  <li><a href="#useclass">Using the Class</a></li>
  <li><a href="#pubvar">Public Variables</a></li>
  <li><a href="#pubfunc">Public Functions</a></li>
  <li><a href="#extend">Extending Class</a></li>
  </ul></li>
<li><a href="#faq">FAQ</a></li>
</ul>
</div>

<div class="content">

<a id="csp"></a>
<h1>Content Security Policy (CSP)</h1>
<p>
CSP is a proposal being talked about by Mozilla developers. The proposal can be viewed here:<br>
<a href="https://wiki.mozilla.org/Security/CSP/Spec">https://wiki.mozilla.org/Security/CSP/Spec</a></p>

<p>
My nutshell interpretation of the proposal is to give client side web browsers the ability to enforce a policy defined by the web master of the web site serving the web page that the client is viewing.</p>
<p>
If it's a policy defined by the web master, why can't the web master implement it? In a perfect world he can, but very often in today's world the web master is not really a code professional, but an everyday person running software (such as a blog or CMS or forum) that he did not write nor fully understands. This often results in XSS (and other) vulnerabilities that are not noticed or closed that allow a malicious individual to inject scripts into the web site for the purpose of attacking other users who visit that web site.</p>
<p>
Sometimes these attacks can remain on the server for quite some time before they are found and dealt with. This is why I am so excited about the Mozilla proposal. With CSP, the web master can define a few simple parameters that alert the web browser that something fishy is going on. Furthermore, the web master can define a URL that the web browser can then use to alert the web master something fishy was attempted.</p>
<p>
See the web page (linked above) for proper details and definition.</p>
<p>
<strong>Disclaimer:</strong> I am not a Mozilla Developer and I am not involved in any of the decision making with respect to the CSP proposal.</p>

<a id="sscsp"></a>
<h1>Server Side CSP Filtering</h1>
<p>
Since it will be some time before CSP capable browsers have significant market share, I decided to implement CSP server side in a PHP class.</p>
<p>
What the class (assuming it properly functions) does is remove any content from the web page that violates the CSP before the web page is even sent to the requesting browser. The beauty of doing it this way is that the user will not have to use a specific browser or install a plugin/add-on in order to benefit from a web master establishing a reasonable CSP policy (is CSP policy redundantly redundant?).</p>
<p>
A web master who implements my class should still send the CSP header to the requesting client, server side CSP can not protect the user from policy violations that result from DHTML modification of the web page. DHTML should only happen via a script that is from an approved domain so the risk is lower, but the risk is still there, especially with the recent scary popularity of web masters using third party hosted JavaScript libraries.</p>

<a id="source"></a>
<h2>Class Source</h2>
<p>
You can view the current development source here: <a href="cspfilter_class.phps">cspfilter_class.phps</a>.</p>
<p>
To download the source with documentation: <a href="http://www.clfsrpm.net/xss/tarball.php">Download</a>. Create a new directory and unpack the archive <em>inside</em> that directory, the tarball does not create a directory for you.</p>

<a id="target"></a>
<h2>Target Audience</h2>
<p>
Anyone with dynamic content, especially dynamic content that displays data not provided by the page programmer.</p>
<p>
I would love to see this class implemented by template developers and web applications commonly used by the general public (IE blogging software, content management software, boards, etc.)</p>

<a id="license"></a>
<h2>License</h2>
<p>
The class is distributed under the terms of the <a href="http://www.opensource.org/licenses/cpl1.0.php">Common Public License, version 1.0</a></p>

<a id="implement"></a>
<h1>CSP Implementation</h1>
<p>
Here is how the script implements CSP:</p>

<a id="cspimage"></a>
<h2>Image Nodes</h2>
<p>
If an <span class="mono">img</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for images, one of two things will happen:</p>
<ol>
<li>If an <span class="mono">alt</span> attribute exists, the <span class="mono">img</span> node is replaced with a <span class="mono">text</span> node containing the contents of the <span class="mono">alt</span> tag. Earlier pre-release versions of the class just removed the <span class="mono">src</span> attribute, but that broke the W3C specification causing valid input to return invalid output after filtering.</li>
<li>If an <span class="mono">alt</span> attribute does not exist, the <span class="mono">img</span> node is simply removed.</li>
</ol>

<h3>Example</h3>

<p>
If viewing this page via <a href="README.html">README.html</a> you will see an image below. If viewing this page via <a href="index.php">index.php</a> you will only see the alt tag.</p>
<p><img src="testimage.jpg" alt="[Test Image. Either your browser is not displaying images or the image was blocked.]" width="300" height="228"></p>

<a id="cspmedia"></a>
<h2>Media Nodes</h2>
<p>
Media nodes consist of the <span class="mono">audio</span> and <span class="mono">video</span> tags that look like they will be part of the <span class="mono">(X)HTML 5</span> specification.</p>
<p>
If a <span class="mono">media</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for media, the <span class="mono">media</span> node is removed.</p>


<a id="cspscript"></a>
<h2>Script Nodes</h2>
<p>
Since there are no circumstances where a <span class="mono">script</span> node may have children in a CSP, any children of a <span class="mono">script</span> node are removed.</p>
<p>
If a <span class="mono">script</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for scripts, the <span class="mono">script</span> node is removed.</p>

<h3>Event Attributes</h3>
<p>
From my understanding of the current CSP recommendation, event attributes are not allowed. All event attributes are therefore removed.</p>

<h3>Example</h3>

<p id="scriptTest">
Either you are viewing the <a href="index.php">index.php</a> version on this page, or you are client side blocking script execution. If you allow scripts to execute, the <a href="README.html">README.html</a> version of this page will have replaced this paragraph.</p>

<a id="cspobject"></a>
<h2>Object / Embed / Applet Nodes</h2>
<p>
If an <span class="mono">object</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for objects, one of two things will happen:</p>
<ol>
<li>If the <span class="mono">object</span> node has children, it is turned into a <span class="mono">div</span> node (without any attributes), the children are preserved.</li>
<li>If the <span class="mono">object</span> node does not have children, it is removed.</li>
</ol>

<h3>Embed</h3>
<p>
The <span class="mono">embed</span> element supposedly is a proprietary tag that has been deprecated by the <span class="mono">object</span> tag, yet I've seen some references to it being included in HTML 5.0 which makes zero sense to me since it does not do anything that can't be done with <span class="mono">object</span>. However, deprecated or not, it is a fairly popular tag, especially for flash.</p>
<p>
The <span class="mono">embed</span> tag is not official (yet), but it seems like it is not allowed to have any children, so any children of an <span class="mono">embed</span> node are removed.</p>
<p>
If an <span class="mono">embed</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for objects, it is removed.</p>

<h3>Applet</h3>
<p>
The <span class="mono">applet</span> tag has been deprecated, you should use <span class="mono">object</span> instead.</p>
<p>
If an <span class="mono">applet</span> node does not have a <span class="mono">code</span> attribute that matches a CSP allowed source for objects, one of two things will happen:</p>
<ol>
<li>If the <span class="mono">applet</span> node has children, it is turned into a <span class="mono">div</span> node (without any attributes), the children are preserved.</li>
<li>If the <span class="mono">applet</span> node does not have children, it is removed.</li>
</ol>

<h3>Example</h3>

<object data="ifobtest.php?type=object" type="text/html" style="width: 100%; border-style: solid;">
<p>
If viewing this page via <a href="README.html">README.html</a> you will see the contents of an object instead of this paragraph. If viewing this page via <a href="index.php">index.php</a> you should see the children of the object node, including this paragraph.</p>
</object>

<a id="cspframe"></a>
<h2>Frame Nodes</h2>
<p>
A <span class="mono">frame</span> node is not allowed to have children by W3C specification, so any children of a <span class="mono">frame</span> node are removed.</p>
<p>
If a <span class="mono">frame</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for frames, it is removed.</p>
<p>
If an <span class="mono">iframe</span> node does not have a <span class="mono">src</span> attribute that matches a CSP allowed source for frames, one of two things will happen:</p>
<ol>
<li>If the <span class="mono">iframe</span> node has children, it is turned into a <span class="mono">div</span> node (without any attributes), the children are preserved.</li>
<li>If the <span class="mono">iframe</span> node does not have children, it is removed.</li>
</ol>

<h3>Example</h3>

<iframe src="ifobtest.php?type=iframe" style="width: 100%;">
<p>
If viewing this page via <a href="README.html">README.html</a> you will see the contents of an iframe instead of this paragraph. If viewing this page via <a href="index.php">index.php</a> you should see the children of the iframe node, including this paragraph.</p>
</iframe>

<a id="cspstyle"></a>
<h2>Style Sheets</h2>
<p>
If the <span class="mono">href</span> attribute of a <span class="mono">link</span> node does not match a CSP allowed host for style sheets, the <span class="mono">link</span> node is removed.</p>

<a id="report"></a>
<h2>Trigger Notification</h2>
<p>
If the CSP has a report URI specified, <strong>and</strong> the <span class="mono">$policyLogFile</span> variable does not point to a real file, code that violated the policy will be reported to that URI using a similar XML syntax as specified in the Mozilla CSP specification. It is up to the web developer to code something that does something useful with the report.</p>

<pre id="treport" class="cspreport">
&lt;cspfilter-report&gt;
  &lt;request&gt;$_SERVER['REQUEST_METHOD'] $_SERVER['REQUEST_URI'] $_SERVER['SERVER_PROTOCOL']&lt;request&gt;
  &lt;request-headers&gt;Some headers related to the request&lt;/request-headers&gt;
  &lt;blocked-uri directive="policy"&gt;blocked resource URI&lt;/blocked-uri&gt;
  &lt;misc&gt;violations that are not a URI resource&lt;/misc&gt;
&lt;/csp-report&gt;
</pre>

<p>
It is very similar to what a CSP aware browser would send, but currently has some differences:</p>
<ol>
   <li>The main node uses the tag name <span class="mono">cspfilter-report</span> opposed to <span class="mono">csp-report</span> to differentiate server side CSP enforcement from what is caught by the requesting client when the report is sent via post to the <span class="mono">report-uri</span>.</li>
   <li>The <span class="mono">blocked-uri</span> element will have an attribute whose name is the policy directive that caused the block and whose value is the policy host expression.</li>
   <li>I've added a <span class="mono">misc</span> node for alterations of the source by the filter that do not involve a blocked URI. The element name of that node may change.</li>
   <li>All reports for a page will be children of a single <span class="mono">cspfilter-report</span> node.</li>
</ol>
<p>
If you have specified a trigger log file, the report will be appended to the log file rather then sent to a report URI. The web server of course must have permission to write to the log file.</p>

<a id="beyondcsp"></a>
<h1>Beyond CSP</h1>
<p>
My class allows for some parameters that are not part of the CSP proposal.</p>

<a id="whitelist"></a>
<h2>Event Attribute Whitelist</h2>
<p>
You can define a white list of event attributes that will not be removed if scripting is allowed. However, if those event attributes have any functions with arguments, the argument will be removed. For example, <span class="mono">&lt;body onload=&quot;alert('Hello');&quot;&gt;</span> would become <span class="mono">&lt;body onload=&quot;alert();&quot;&gt;</span>.</p>
<p>
It is my hope that the final CSP recommendation will at least allow event handlers that do not contain any functions with arguments. Client side form validation really needs them. That's why my class allows for them.</p>

<a id="scriptinhead"></a>
<h2>Script Only in Head</h2>
<p>
This allows you to forbid any script nodes regardless of the <span class="mono">src</span> attribute that do not appear in the document head. It is useful if you declare third party JavaScript sources for your page to use but want to make sure your users can not inject a script from the same third party script host.</p>

<a id="otherchecks"></a>
<h2>Other Checks</h2>

<h3>Attribute Content</h3>
<p>
The following are not allowed in any attribute and are removed if they are found:</p>
<ul>
<li>javascript:</li>
<li>mocha:</li>
<li>vbscript:</li>
</ul>

<h3>Redundant Nodes</h3>
<p>
By W3C specification some nodes, such as <span class="mono">title</span>, are only allowed to occur once. The class assumes something fishy is being attempted and removes additional occurrences of those nodes.</p>

<h3>Head Section</h3>
<p>
By W3C specification, some nodes may only occur as children of the <span class="mono">head</span> node. For example the <span class="mono">meta</span> node. When those nodes are not direct children of the <span class="mono">head</span> node, the output filter considers it to be suspicious and they are removed.</p>

<h3>Nodes That Should Not Have Children</h3>
<p>
By W3C specification, some nodes, such as <span class="mono">hr</span>, are not allowed to have children. When those nodes are found to have children, the output filter considers it to be suspicious and the child nodes are removed.</p>

<a id="demo"></a>
<h1>Live Testing of Filter Class</h1>
<p>
You can test the current implementation of the CSP filter class here:<br>
<a href="dom_script_test.php">dom_script_test.php</a></p>
<p>
No intentional import filtering of code entered into the <span class="mono">textarea</span> is performed. The text area upon submit is eaten by DOMDocument <span class="mono">importHTML()</span> which does do some minimal filtering of it's own, but if the code you enter is clean HTML it should be properly imported without modification and you can test how the class filters the input. Filtered input is displayed as XML at the bottom of the page after you hit submit so that you do not have to continuously view the page HTML source (which can sometimes fail in some browsers, fetching a new copy of the page via get to show the source) to see how it filtered your input.</p>

<a id="Coleoptera"></a>
<h1>Known Bugs</h1>
<dl>
<dt class="bug">IDNA needs testing.</dt>
   <dd>Zero testing has been done with host names and server paths that use IDNA.</dd>
<dt class="bug">Not Fully Compliant</dt>
   <dd>Need to bring into compliance with <a href="https://wiki.mozilla.org/Security/CSP/Spec">https://wiki.mozilla.org/Security/CSP/Spec</a> before 1.0</dd>
<dt class="bug">Does not check for existing meta tag</dt>
   <dd>Need to check the DOM for an existing CSP meta tag and yank it if it exists.</dd>
</dl>

<a id="checkme"></a>
<h2>Needs Checking</h2>
<p>
The <span class="mono">obfus()</span> function needs some heavy duty checking. I initially borrowed some of the regex in it from another source, and found the regex to be improper. The regex I replaced needs to be brutally tested to make sure it does what it is suppose to do, and the regex I did not replace needs thorough testing to make sure it doesn't need replacing.</p>
<p>
I need to make sure I have the scope of the <span class="mono">base</span> tag correct, which elements it impacts and which elements it does not impact.</p>
<p>
For script attributes, I need to make sure I catch all methods for invoking client side scripting. Right now it checks for <span class="mono">javascript: vbscript: mocha:</span> but there may be others it needs to check for?</p>
<p>
I need to make sure my list of event attributes is complete, and that I properly understand what CSP wants to do with event handlers.</p>
<p>
I need to check whether or not namespaced elements are legal in XHTML, right now I only check for namespaced attributes.</p>
<p>
I really need to make sure there are no cases where W3C valid input result is invalid output after filtering.</p>

<a id="questions"></a>
<h2>Questions About the Spec</h2>
<p>
If <span class="mono">style-src</span> does not include the host the page is being served from, should <span class="mono">style</span> elements and <span class="mono">style</span> attributes be yanked?</p>
<p>
Does the host expression list allow wildcards that are not at beginning of word?</p>

<a id="usage"></a>
<h1>Class Usage</h1>

<a id="notInput"></a>
<h2>Not a Substitute for Input Filter</h2>
<p>
You still need to filter your input, for a variety of reasons (IE you don't want an XSS vector stored in your database). If your input filtering is good and is configured to properly enforce your policy, the class should never be triggered to modify output generated by user input. The class is a second line of defense for situations where input validation failed to catch something.</p>
<p>
If you are developing code and need an input filter, you are probably better off using something like <a href="http://htmlpurifier.org/">HTML Purifier</a> rather than writing a class/function of your own.</p>

<a id="completeDocument"></a>
<h2>Class Operates on Complete Document</h2>
<p>
To use the class, you need to fully construct your HTML/XHTML document <em>BEFORE</em> using the class to filter it. Most (all?) popular template systems allow for this with relative ease.</p>
<p>
If you mix HTML with PHP and/or use the PHP <span class="mono">print()</span> and <span class="mono">echo()</span> functions to send output to the browser before your PHP has finished running, you can not use this class. Since HTTP is a stateless protocol, sending data before you have finished building the document IMHO is poor design anyway, but doing so is very common. It won't work with this class though.</p>
<p>
With respect to template systems, I'm not too familiar with them but it looks like some of them allow the page to be built in chunks and then sent as chunks instead of sent all at once. It would be better to create a buffer and append all your chunks to the buffer before sending them, and then pass the entire buffer through the output class.</p>

<a id="php5"></a>
<h2>Class requires PHP 5 with XML support</h2>
<p>
The class requires your document be in the form of a PHP 5 DOMDocument object. If your PHP installation does not support the PHP XML functions, you either need to recompile PHP or install the XML loadable module.</p>
<p>
To import your document into a DOMDocument object:</p>
<pre>
$domdoc = new DOMDocument("1.0","utf-8");
$domdoc->preserveWhiteSpace = false; // optional
$domdoc->formatOutput = true; // optional but makes for prettier output
$domdoc->loadHTML($yourhtmlasbuffer); // use loadXML() for well formed XHTML
</pre>
<p>
Now your HTML/XHTML is ready for filtering.</p>
<p>
For an example of this method, see the PHP source of <a href="index.phps">this page</a></p>

<a id="tidy"></a>
<h2>Be Careful with Tidy</h2>
<p>
It may be tempting to pass your completed document through tidy before feeding it to a DOMDocument class for filtering. Be aware that tidy will move some tags into the <span class="mono">head</span> section that you do not want there. For example, if a malicious user manages to sneak a <span class="mono">meta</span> tag past your input filtering, tidy will then help the malicious user by moving that <span class="mono">meta</span> tag into the <span class="mono">head</span> section where the output filter will merrily allow it.</p>
<p>
There may be a tidy option to prevent this, I don't know.</p>
<p>
It should be relatively safe to use tidy as part of an import filter, as long as the tidy option <span class="mono">show-body-only</span> is specified as <span class="mono">true</span>.</p>

<a id="idna"></a>
<h2>Internationalized Domain Names for Applications</h2>
<p>
This functionallity has not yet been tested.</p>
<p>
The CSP spec says that the CSP directives for IDNA needs to be punycode. The class does not do that for you. However, it will attempt to convert the source attributes to punycode for you if you if you install the IDNA Convert class.</p>
<p>
You can get the class here: <a href="http://www.phpclasses.org/browse/package/1509.html">http://www.phpclasses.org/browse/package/1509.html</a></p>
<p>
The class is not included with this distribution. Once you have the class, in order for cspfilter to use it you need to include the class, preferably somewhere in your script before you use the cspfilter class, or alternatively you can modify the cspfilter_class.php file and include it there.</p>
<p>
I would be very grateful if someone with more IDNA knowledge than me could do some thorough testing of it. The <a href="dom_script_test.php">live test page</a> (hosted on clfsrpm.net) includes the necessary class and should work for IDNA testing (for html source, the CSP policy input fields must be entered as punycode encoded).</p>

<a id="useclass"></a>
<h2>Using the Class</h2>
<p>
Initiate the class and tell it about your document:</p>
<pre>
$filter = new cspfilter($domdoc);
</pre>

<p>
Specify the class option settings:</p>
<pre>
$filter->httphost = "www.yourdomain.com";
$filter->csp['allow'] = 'none';
$filter->csp['img-src'] = '*.yourdomain.com *.photobucket.com www.w3.org';
</pre>

<p>
Run the filter:</p>
<pre>
$filter->processData();
</pre>

<p>
Optionally apply the CSP meta tag or send the CSP header:</p>

<pre>
$filter->cspHeader = true; // defaults to false which creates meta tag instead of header
$filter->makeCSP(); // creates and applies the meta tag or sends the header
</pre>

<p>
Now send the page to the requesting browser:</p>
<pre>
print $domdoc->saveHTML(); //for XHTML - use saveXML();
</pre>

<a id="pubvar"></a>
<h2>Public Class Variable</h2>

<h3>CSP Specific Variables</h3>
<p>
The class has a public array called <span class="mono">csp</span> that has seven indexes. These indexes are identical to the names and settings used by the CSP recommendation and take the same syntax for their setting.</p>
<dl>
<dt>$csp['allow']</dt>
   <dd>Default policy. Set to <span class="mono">self</span> to default allow sources that originate from same domain as page is being served from, set to <span class="mono">none</span> to default deny (recommended, and default if not set), or set to a space delimited list of hosts that resources may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['img-src']</dt>
   <dd>Override default policy for images. Set to <span class="mono">self</span> to allow images served from same host as page is being served from, or set to <span class="mono">none</span> to forbid images from being served, or set to a space delimited list of hosts images may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['media-src']</dt>
   <dd>Override default policy for media (audio,video tags). Set to <span class="mono">self</span> to allow media served from same host as page is being served from, or set to <span class="mono">none</span> to forbid media from being served, or set to a space delimited list of hosts media may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['script-src']</dt>
   <dd>Override default policy for scripts. Set to <span class="mono">self</span> to allow scripts served from same host as page is being served from, or set to <span class="mono">none</span> to forbid all script execution, or set to a space delimited list of hosts scripts may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['object-src']</dt>
   <dd>Override default policy for object, embed, applet. Set to <span class="mono">self</span> to allow objects served from same host as page is being served from, or set to <span class="mono">none</span> to forbid objects from being served, or set to a space delimited list of hosts objects may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['frame-src']</dt>
   <dd>Override default policy for frames and iframes. Set to <span class="mono">self</span> to allow frames served from same host as page is being served from, or set to <span class="mono">none</span> to forbid frames from being served, or set to a space delimited list of hosts objects may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['frame-ancestors']</dt>
   <dd>Override default policy for frame ancestors. Note that there is no way to server side filter frame-ancestors, frame-ancestor filtering can only be done by client side CSP.</dd>
<dt>$csp['style-src']</dt>
   <dd>Override default policy for style sheet source. Set to <span class="mono">self</span> to allow style sheets served from same host as page is being served from, or set to <span class="mono">none</span> to forbid all style sheets, or set to a space delimited list of hosts style sheets may be served from (* as leading wild card allowed, IE *.example.com).</dd>
<dt>$csp['report-uri']</dt>
   <dd>URI that the browser should report policy violations to.</dd>
</dl>
<p>
<strong>NOTE:</strong> cspfilter does not use the <span class="mono">policy-uri</span> directive. Specify your desired policy using the above array variables in your script. If you want to set site wide policy, you can create a class that extends the cspfilter class and define your defaults there. Why? See the <a href="#faq">FAQ</a>.</p>

<h3>Non CSP Variables</h3>
<dl>
   <dt>$version</dt>
   <dd>The version of the class. Not used by the class. This variable should be considered read-only, but unfortunately there isn't (yet, appears to be in CVS) a simple way to declare public class variables as read-only. Yes, I've seen the hacks that do it, but since changing that variable will not break anything they don't interest me. Just understand there isn't a need to ever alter it.</dd>
   <dt>$cspHeader</dt>
   <dd>Boolean. Only used by the <span class="mono">makeCSP()</span> function. If set to false (default) then <span class="mono">makeCSP()</span> creates a CSP meta tag and puts it in the <span class="mono">head</span> section of your document. If set to true, <span class="mono">makeCSP()</span> send an HTTP header to notify the client browser of the CSP for the page.</dd>
   <dt>$scriptOnlyInHead</dt>
   <dd>Boolean. If set to true, the <span class="mono">script</span> node is only allowed in the document <span class="mono">head</span> section.</dd>
   <dt>$httphost</dt>
   <dd>String. The fully qualified host name the page is being sent from. The class does detect this from the <span class="mono">$_SERVER["HTTP_HOST"]</span> global, but that global can be impacted by headers the client sends, so it should not be trusted. It is better to specify the variable value.</dd>
   <dt>$eventWhitelist</dt>
   <dd>Array. If scripting is allowed, this array contains the name of event attributes that the filter is not to remove from the document.</dd>
   <dt>$policyLogFile</dt>
   <dd>String. If specified and the file exists, policy violations will be logged to this file. Even if <span class="mono">$csp['report-uri']</span> is set, the <span class="mono">$policyLogFile</span> variable takes precedence so that the class does not need to make an HTTP connection.</dd>
</dl>

<a id="pubfunc"></a>
<h2>Public Class Functions</h2>
<dl>
   <dt>cspfilter()</dt>
   <dd>Constructor function that is run whenever a new instance of the class is created. There is no need to ever call this class directly. Requires a DOMDocument object as argument.</dd>
   <dt>processData()</dt>
   <dd>No Arguments. Applies the filtering to the DOMDocument object specified when the class is initiated according to the rules specified by the public class variables.</dd>
   <dt>makeCSP()</dt>
   <dd>Optional, but recommended. No arguments. Either creates a <span class="mono">meta</span> node specifying the CSP or sends an HTTP header specifying the CSP.</dd>
</dl>

<a id="extend"></a>
<h2>Extending The Class</h2>
<p>
One thing you can do is to create an extension to the class that specifies the base policies you want to enforce. You can still over ride them on a per page basis. Here is an example:</p>
<pre>
&lt;?php
<span class="green">require_once(</span><span class="red">'cspfilter_class.php'</span><span class="green">);</span>

<span class="green">class</span> MyCSP <span class="green">extends</span> cspfilter <span class="green">{</span>
   <span class="green">var</span> $csp <span class="green">=</span> <span class="green">Array(</span><span class="red">'allow'</span>    <span class="green">=&gt;</span> <span class="red">'none'</span><span class="green">,</span>
            <span class="red">'img-src'</span>          <span class="green">=&gt;</span> <span class="red">'self'</span><span class="green">,</span>
            <span class="red">'media-src'</span>        <span class="green">=&gt;</span> <span class="red">''</span><span class="green">,</span>
            <span class="red">'script-src'</span>       <span class="green">=&gt;</span> <span class="red">''</span><span class="green">,</span>
            <span class="red">'object-src'</span>       <span class="green">=&gt;</span> <span class="red">''</span><span class="green">,</span>
            <span class="red">'frame-src'</span>        <span class="green">=&gt;</span> <span class="red">''</span><span class="green">,</span>
            <span class="red">'frame-ancestors'</span>  <span class="green">=&gt;</span> <span class="red">''</span><span class="green">,</span>
            <span class="red">'style-src'</span>        <span class="green">=&gt;</span> <span class="red">'self'</span><span class="green">,</span>
            <span class="red">'report-uri'</span>       <span class="green">=&gt;</span> <span class="red">''</span><span class="green">);</span>
   <span class="green">var</span> $cspHeader     <span class="green">=</span> true<span class="green">;</span>
   <span class="green">var</span> $policyLogFile <span class="green">=</span> <span class="red">'/path/to/log/csplog.xml'</span><span class="green">;</span>
   <span class="green">var</span> $httphost      <span class="green">=</span> <span class="red">'www.yourdomain.net'</span><span class="green">;</span>
   <span class="green">}</span>
?&gt;
</pre>
<p>
Require the file containing that code and then you can call the class in your page via:</p>
<pre>
$filter = new MyCSP($domdoc);
</pre>
<p>
The settings specified in the class extension will be used.</p>

<a id="faq"></a>
<h1>FAQ</h1>
<p>
OK, these are not really frequently asked, but they might be.</p>
<dl>
<dt>Why do you not support the policy-uri directive?</dt>
   <dd>There are several possible sources for policy. One is the meta tag, one is the <span class="mono">policy-uri</span>, and one of course is the <span class="mono">$csp</span> array that the class uses.</dd>
<dt>&nbsp;</dt>
   <dd>I actually started to write code that merged the different possible sources using set intersection, but to do it right it started to get more and more complex. The more complex something is, the more likely it has bugs and the more difficult it is to maintain, so I opted for a KISS philosophy. Ignore any directives set in a policy file or in a meta tag of the DOM.</dd>
<dt>&nbsp;</dt>
   <dd>Since the default policy for the class is <span class="mono">none</span> ignoring those other methods is safe to do. Also, the headers / meta tag are not suppose to use the <span class="mono">policy-uri</span> unless that is the <em>only</em> directive sent, but if a user wants to use a site wide policy, the user can just extend the class and define the site wide policy there via the <span class="mono">$csp</span> variables.</dd>
<dt>When will the class support International Host Names?</dt>
   <dd>I think it does now, but I have not done any testing whatsoever. The CSP spec states that the CSP directives need to be in punycode. I do not attempt to do that for you (should I??). I do however attempt to convert sources to punycode for checking against the CSP policy.</dd>
<dt>Do you have a bugzilla?</dt>
   <dd>No. I'm just a regular guy who wrote this class for my own purposes and decided that others could benefit. Feel free to send bug reports to <a href="mailto:hide@address.com">hide@address.com</a>.</dd>
<dt>Why do I have to have the page fully constructed before sending to use your class?</dt>
   <dd>Because the class is an <strong>output</strong> filter that operates on a DOMDocument. You can cheat and alter the DOMDocument after running the filter, but then any content after running the filter is not filtered.</dd>
<dt>Are you going to write a CSP input filter?</dt>
   <dd>From scratch? No. At some point I may try to extend the HTML Purifier class to add some CSP checks on input, but if (and I stress the if) I ever do, it probably won't be for awhile.</dd>
   
   
</dl>


<p>
<a href="http://validator.w3.org/check?uri=referer"><img
   src="http://www.w3.org/Icons/valid-html401-blue"
   alt="Valid HTML 4.01 Transitional" height="31" width="88" style="border: none;"></a>
</p>
</div>
</body></html>
Return current item: CSP Filter