mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-07-12 10:16:18 +02:00
[3.1.1] Implement %URI.SecureMunge and %URI.SecureMungeSecretKey, thanks Chris!
- URIFilter->prepare can return false in order to abort loading of the filter - Implemented post URI filtering. Set member variable $post to true to set a URIFilter as such. git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1772 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
@ -178,6 +178,7 @@ require 'HTMLPurifier/URIFilter/DisableExternal.php';
|
||||
require 'HTMLPurifier/URIFilter/DisableExternalResources.php';
|
||||
require 'HTMLPurifier/URIFilter/HostBlacklist.php';
|
||||
require 'HTMLPurifier/URIFilter/MakeAbsolute.php';
|
||||
require 'HTMLPurifier/URIFilter/SecureMunge.php';
|
||||
require 'HTMLPurifier/URIScheme/ftp.php';
|
||||
require 'HTMLPurifier/URIScheme/http.php';
|
||||
require 'HTMLPurifier/URIScheme/https.php';
|
||||
|
@ -172,6 +172,7 @@ require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternal.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternalResources.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIFilter/HostBlacklist.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIFilter/MakeAbsolute.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIFilter/SecureMunge.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIScheme/ftp.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIScheme/http.php';
|
||||
require_once $__dir . '/HTMLPurifier/URIScheme/https.php';
|
||||
|
@ -50,6 +50,10 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
|
||||
$result = $scheme_obj->validate($uri, $config, $context);
|
||||
if (!$result) break;
|
||||
|
||||
// Post chained filtering
|
||||
$result = $uri_def->postFilter($uri, $config, $context);
|
||||
if (!$result) break;
|
||||
|
||||
// survived gauntlet
|
||||
$ok = true;
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
33
library/HTMLPurifier/ConfigSchema/schema/URI.SecureMunge.txt
Normal file
33
library/HTMLPurifier/ConfigSchema/schema/URI.SecureMunge.txt
Normal file
@ -0,0 +1,33 @@
|
||||
URI.SecureMunge
|
||||
TYPE: string/null
|
||||
VERSION: 3.1.1
|
||||
DEFAULT: NULL
|
||||
--DESCRIPTION--
|
||||
<p>
|
||||
Like %URI.Munge, this directive munges browsable external resources
|
||||
into another URI redirection service. %URI.SecureMunge accepts a URI
|
||||
with a %s located where the original URI should be substituted in,
|
||||
and %t located where the secure checksum should be provided.
|
||||
However, this directive affords
|
||||
an additional level of protection by generating a secure checksum from
|
||||
the URI as well as a secret key provided by %URI.SecureMungeSecretKey.
|
||||
Any redirector script can check this key by using:
|
||||
</p>
|
||||
|
||||
<pre>$checksum === sha1($secret_key . ':' . $url)</pre>
|
||||
|
||||
<p>
|
||||
If the output is TRUE, the redirector script should accept the URI.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Please note that it would still be possible for an attacker to procure
|
||||
secure hashes en-mass by abusing your website's Preview feature or the
|
||||
like, but this service affords an additional level of protection
|
||||
that should be combined with website blacklisting.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>This is a post-filter.</strong> This filter may conflict with other
|
||||
post-filters that deal with external links.
|
||||
</p>
|
@ -0,0 +1,11 @@
|
||||
URI.SecureMungeSecretKey
|
||||
TYPE: string/null
|
||||
VERSION: 3.1.1
|
||||
DEFAULT: NULL
|
||||
--DESCRIPTION--
|
||||
<p>
|
||||
This is the secret key used in conjunction with %URI.SecureMunge. Your
|
||||
redirector script needs to know about this key, and no one else should
|
||||
know about this key. Please see the above
|
||||
directive for more details.
|
||||
</p>
|
@ -5,6 +5,7 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
|
||||
|
||||
public $type = 'URI';
|
||||
protected $filters = array();
|
||||
protected $postFilters = array();
|
||||
protected $registeredFilters = array();
|
||||
|
||||
/**
|
||||
@ -34,8 +35,13 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
|
||||
}
|
||||
|
||||
public function addFilter($filter, $config) {
|
||||
$filter->prepare($config);
|
||||
$this->filters[$filter->name] = $filter;
|
||||
$r = $filter->prepare($config);
|
||||
if ($r === false) return; // null is ok, for backwards compat
|
||||
if ($filter->post) {
|
||||
$this->postFilters[$filter->name] = $filter;
|
||||
} else {
|
||||
$this->filters[$filter->name] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
protected function doSetup($config) {
|
||||
@ -66,8 +72,16 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
|
||||
}
|
||||
|
||||
public function filter(&$uri, $config, $context) {
|
||||
foreach ($this->filters as $name => $x) {
|
||||
$result = $this->filters[$name]->filter($uri, $config, $context);
|
||||
foreach ($this->filters as $name => $f) {
|
||||
$result = $f->filter($uri, $config, $context);
|
||||
if (!$result) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postFilter(&$uri, $config, $context) {
|
||||
foreach ($this->postFilters as $name => $f) {
|
||||
$result = $f->filter($uri, $config, $context);
|
||||
if (!$result) return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -19,10 +19,15 @@ abstract class HTMLPurifier_URIFilter
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* True if this filter should be run after scheme validation.
|
||||
*/
|
||||
public $post = false;
|
||||
|
||||
/**
|
||||
* Performs initialization for the filter
|
||||
*/
|
||||
public function prepare($config) {}
|
||||
public function prepare($config) {return true;}
|
||||
|
||||
/**
|
||||
* Filter a URI object
|
||||
|
@ -6,6 +6,7 @@ class HTMLPurifier_URIFilter_HostBlacklist extends HTMLPurifier_URIFilter
|
||||
protected $blacklist = array();
|
||||
public function prepare($config) {
|
||||
$this->blacklist = $config->get('URI', 'HostBlacklist');
|
||||
return true;
|
||||
}
|
||||
public function filter(&$uri, $config, $context) {
|
||||
foreach($this->blacklist as $blacklisted_host_fragment) {
|
||||
|
@ -11,14 +11,15 @@ class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter
|
||||
$def = $config->getDefinition('URI');
|
||||
$this->base = $def->base;
|
||||
if (is_null($this->base)) {
|
||||
trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_ERROR);
|
||||
return;
|
||||
trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$this->base->fragment = null; // fragment is invalid for base URI
|
||||
$stack = explode('/', $this->base->path);
|
||||
array_pop($stack); // discard last segment
|
||||
$stack = $this->_collapseStack($stack); // do pre-parsing
|
||||
$this->basePathStack = $stack;
|
||||
return true;
|
||||
}
|
||||
public function filter(&$uri, $config, $context) {
|
||||
if (is_null($this->base)) return true; // abort early
|
||||
|
32
library/HTMLPurifier/URIFilter/SecureMunge.php
Normal file
32
library/HTMLPurifier/URIFilter/SecureMunge.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
class HTMLPurifier_URIFilter_SecureMunge extends HTMLPurifier_URIFilter
|
||||
{
|
||||
public $name = 'SecureMunge';
|
||||
public $post = true;
|
||||
private $target, $secretKey, $parser;
|
||||
public function prepare($config) {
|
||||
$this->target = $config->get('URI', 'SecureMunge');
|
||||
$this->secretKey = $config->get('URI', 'SecureMungeSecretKey');
|
||||
$this->parser = new HTMLPurifier_URIParser();
|
||||
if (!$this->secretKey) {
|
||||
trigger_error('URI.SecureMunge is being ignored due to lack of value for URI.SecureMungeSecretKey', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public function filter(&$uri, $config, $context) {
|
||||
if (!$this->target || !$this->secretKey) return true;
|
||||
$scheme_obj = $uri->getSchemeObj($config, $context);
|
||||
if (!$scheme_obj) return true; // ignore unknown schemes, maybe another postfilter did it
|
||||
if (is_null($uri->host) || empty($scheme_obj->browsable)) {
|
||||
return true;
|
||||
}
|
||||
$string = $uri->toString();
|
||||
$checksum = sha1($this->secretKey . ':' . $string);
|
||||
$new_uri = str_replace('%s', rawurlencode($string), $this->target);
|
||||
$new_uri = str_replace('%t', $checksum, $new_uri);
|
||||
$uri = $this->parser->parse($new_uri); // overwrite
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user