The branch, master has been updated via a418fa95b962d77a614a0cbf66626123db4fc87f (commit) via 8d589ed83e27f3d7a466df97bc9726449f3d5ede (commit) via ef4f1717b2a9d97aa346fb5bd2267fb67dddf474 (commit) via 7b6043c6198a0d8e1ef23025ee315e5028c0d271 (commit) via 0c57cb20e23a58736621e5dbab113bda6b690f3e (commit) via 55c6412e6c4a6e1d4555978e8a8d13a4159dc5aa (commit) via a4807a8e7c07b7d2d6d9060af1f569b513b48038 (commit) from 3104583db2e302d2c237e715132f94c3170e350e (commit)
- Log ----------------------------------------------------------------- commit a418fa95b962d77a614a0cbf66626123db4fc87f Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 14:13:03 2011 +0200
Add testcase for combined link and XSS attempt
commit 8d589ed83e27f3d7a466df97bc9726449f3d5ede Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 14:12:22 2011 +0200
Fix matching of tags without target
commit ef4f1717b2a9d97aa346fb5bd2267fb67dddf474 Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 14:10:22 2011 +0200
Add testcase for documenation link
commit 7b6043c6198a0d8e1ef23025ee315e5028c0d271 Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 14:08:46 2011 +0200
Re-enable test for links
commit 0c57cb20e23a58736621e5dbab113bda6b690f3e Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 14:05:57 2011 +0200
Use preg_replace_callback for interpreting [a@...]
This way we need to evaluate regullar expression only once and can convert all correct links rather than replacing none in case one string is broken.
commit 55c6412e6c4a6e1d4555978e8a8d13a4159dc5aa Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 13:56:07 2011 +0200
Add documentation
commit a4807a8e7c07b7d2d6d9060af1f569b513b48038 Author: Michal Čihař mcihar@suse.cz Date: Mon Jul 25 13:54:09 2011 +0200
Improve check for valid links
-----------------------------------------------------------------------
Summary of changes: libraries/sanitizing.lib.php | 88 +++++++++++++++++++++++----------- test/libraries/PMA_sanitize_test.php | 17 +++++- 2 files changed, 74 insertions(+), 31 deletions(-)
diff --git a/libraries/sanitizing.lib.php b/libraries/sanitizing.lib.php index d0d3ba8..86cd13c 100644 --- a/libraries/sanitizing.lib.php +++ b/libraries/sanitizing.lib.php @@ -7,6 +7,59 @@ */
/** + * Checks whether given link is valid + * + * @param $url string URL to check. + * + * @return bool True if string can be used as link. + */ +function PMA_check_link($url) { + if (substr($url, 0, 7) == 'http://') { + return true; + } elseif (substr($url, 0, 8) == 'https://') { + return true; + } elseif (!defined('PMA_SETUP') && substr($url, 0, 20) == './Documentation.html') { + return true; + } elseif (defined('PMA_SETUP') && substr($url, 0, 21) == '../Documentation.html') { + return true; + } + return false; +} + +/** + * Callback function for replacing [a@link@target] links in bb code. + * + * @param $found array preg matches + * + * @return string Replaced string + */ +function PMA_replace_bb_link($found) { + /* Check for valid link */ + if (! PMA_check_link($found[1])) { + return $found[0]; + } + /* a-z and _ allowed in target */ + if (! empty($found[3]) && preg_match('/[^a-z_]+/i', $found[3])) { + return $found[0]; + } + + /* Construct target */ + $target = ''; + if (! empty($found[3])) { + $target = ' target="' . $found[3] . '"'; + } + + /* Construct url */ + if (substr($found[1], 0, 4) == 'http') { + $url = PMA_linkURL($found[1]); + } else { + $url = $found[1]; + } + + return '<a href="' . $url . '"' . $target . '>'; +} + +/** * Sanitizes $message, taking into account our special codes * for formatting. * @@ -30,6 +83,7 @@ function PMA_sanitize($message, $escape = false, $safe = false) if (!$safe) { $message = strtr($message, array('<' => '<', '>' => '>')); } + /* Interpret bb code */ $replace_pairs = array( '[i]' => '<em>', // deprecated by em '[/i]' => '</em>', // deprecated by em @@ -50,6 +104,7 @@ function PMA_sanitize($message, $escape = false, $safe = false) '[sup]' => '<sup>', '[/sup]' => '</sup>', ); + /* Adjust links for setup, which lives in subfolder */ if (defined('PMA_SETUP')) { $replace_pairs['[a@Documentation.html'] = '[a@../Documentation.html'; } else { @@ -57,36 +112,13 @@ function PMA_sanitize($message, $escape = false, $safe = false) } $message = strtr($message, $replace_pairs);
- $pattern = '/[a@([^"@]*)(@([^]"]*))?]/'; + /* Match links in bb code ([a@url@target], where @target is options) */ + $pattern = '/[a@([^]"@]*)(@([^]"]*))?]/';
- if (preg_match_all($pattern, $message, $founds, PREG_SET_ORDER)) { - $valid_links = array( - 'http', // default http:// links (and https://) - ); - if (defined('PMA_SETUP')) { - $valid_links[] = '../D'; // ./Documentation - } else { - $valid_links[] = './Do'; // ./Documentation - } - - foreach ($founds as $found) { - // only http... and ./Do... allowed - if (! in_array(substr($found[1], 0, 4), $valid_links)) { - return $message; - } - // a-z and _ allowed in target - if (! empty($found[3]) && preg_match('/[^a-z_]+/i', $found[3])) { - return $message; - } - } - - if (substr($found[1], 0, 4) == 'http') { - $message = preg_replace($pattern, '<a href="' . PMA_linkURL($found[1]) . '" target="\3">', $message); - } else { - $message = preg_replace($pattern, '<a href="\1" target="\3">', $message); - } - } + /* Find and replace all links */ + $message = preg_replace_callback($pattern, 'PMA_replace_bb_link', $message);
+ /* Possibly escape result */ if ($escape) { $message = htmlspecialchars($message); } diff --git a/test/libraries/PMA_sanitize_test.php b/test/libraries/PMA_sanitize_test.php index 0e7704c..d88a82c 100644 --- a/test/libraries/PMA_sanitize_test.php +++ b/test/libraries/PMA_sanitize_test.php @@ -10,6 +10,7 @@ * Include to test */ require_once 'libraries/sanitizing.lib.php'; +require_once 'libraries/url_generating.lib.php'; require_once 'libraries/core.lib.php';
class PMA_sanitize_test extends PHPUnit_Framework_TestCase @@ -20,13 +21,23 @@ class PMA_sanitize_test extends PHPUnit_Framework_TestCase PMA_sanitize('[a@javascript:alert('XSS');@target]link[/a]')); }
-/* public function testLink() { - $this->assertEquals('<a href="http://www.phpmyadmin.net/" target="target">link</a>', + $this->assertEquals('<a href="./url.php?url=http%3A%2F%2Fwww.phpmyadmin.net%2F" target="target">link</a>', PMA_sanitize('[a@http://www.phpmyadmin.net/@target%5Dlink%5B/a]')); } -*/ + + public function testLinkDoc() + { + $this->assertEquals('<a href="./Documentation.html">doc</a>', + PMA_sanitize('[a@./Documentation.html]doc[/a]')); + } + + public function testLinkAndXssInHref() + { + $this->assertEquals('<a href="./Documentation.html">doc</a>[a@javascript:alert('XSS');@target]link</a>', + PMA_sanitize('[a@./Documentation.html]doc[/a][a@javascript:alert('XSS');@target]link[/a]')); + }
public function testHtmlTags() {
hooks/post-receive