mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 13:02:07 +02:00
MDL-48546 filters: ReDoS protection for multimedia links.
This commit is contained in:
parent
ac667aa0b7
commit
75cb0ffffe
@ -68,18 +68,52 @@ class filter_mediaplugin extends moodle_text_filter {
|
||||
// Check SWF permissions.
|
||||
$this->trusted = !empty($options['noclean']) or !empty($CFG->allowobjectembed);
|
||||
|
||||
// Handle all links that contain any 'embeddable' marker text (it could
|
||||
// do all links, but the embeddable markers thing should make it faster
|
||||
// by meaning for most links it doesn't drop into PHP code).
|
||||
$newtext = preg_replace_callback($re = '~<a\s[^>]*href="([^"]*(?:' .
|
||||
$this->embedmarkers . ')[^"]*)"[^>]*>([^>]*)</a>~is',
|
||||
array($this, 'callback'), $text);
|
||||
// Looking for tags.
|
||||
$matches = preg_split('/(<a\s[^>]*>)/i', $text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
if (empty($newtext) or $newtext === $text) {
|
||||
// error or not filtered
|
||||
if (!$matches) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
// Regex to find media extensions in an <a> tag.
|
||||
$re = '~<a\s[^>]*href="([^"]*(?:' . $this->embedmarkers . ')[^"]*)"[^>]*>([^>]*)</a>~is';
|
||||
|
||||
$newtext = '';
|
||||
$validtag = '';
|
||||
$sizeofmatches = count($matches);
|
||||
|
||||
// We iterate through the given string to find valid <a> tags
|
||||
// and build them so that the callback function can check it for
|
||||
// embedded content. Then we rebuild the string.
|
||||
foreach ($matches as $idx => $tag) {
|
||||
if (preg_match('|</a>|', $tag) && !empty($validtag)) {
|
||||
$validtag .= $tag;
|
||||
|
||||
// Given we now have a valid <a> tag to process it's time for
|
||||
// ReDoS protection. Stop processing if a word is too large.
|
||||
if (strlen($validtag) < 4096) {
|
||||
$processed = preg_replace_callback($re, array($this, 'callback'), $validtag);
|
||||
}
|
||||
// Rebuilding the string with our new processed text.
|
||||
$newtext .= !empty($processed) ? $processed : $validtag;
|
||||
// Wipe it so we can catch any more instances to filter.
|
||||
$validtag = '';
|
||||
$processed = '';
|
||||
} else if (preg_match('/<a\s[^>]*/', $tag) && $sizeofmatches > 1) {
|
||||
// Looking for a starting <a> tag.
|
||||
$validtag = $tag;
|
||||
} else {
|
||||
// If we have a validtag add to that to process later,
|
||||
// else add straight onto our newtext string.
|
||||
if (!empty($validtag)) {
|
||||
$validtag .= $tag;
|
||||
} else {
|
||||
$newtext .= $tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the same string except processed by the above.
|
||||
return $newtext;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,15 @@ class filter_mediaplugin_testcase extends advanced_testcase {
|
||||
|
||||
$filterplugin = new filter_mediaplugin(null, array());
|
||||
|
||||
$longurl = '<a href="http://moodle/.mp4">my test file</a>';
|
||||
$longhref = '';
|
||||
|
||||
do {
|
||||
$longhref .= 'a';
|
||||
} while(strlen($longhref) + strlen($longurl) < 4095);
|
||||
|
||||
$longurl = '<a href="http://moodle/' . $longhref . '.mp4">my test file</a>';
|
||||
|
||||
$validtexts = array (
|
||||
'<a href="http://moodle.org/testfile/test.mp3">test mp3</a>',
|
||||
'<a href="http://moodle.org/testfile/test.ogg">test ogg</a>',
|
||||
@ -76,7 +85,9 @@ class filter_mediaplugin_testcase extends advanced_testcase {
|
||||
|
||||
href="http://moodle.org/testfile/test.avi">test mp3
|
||||
</a>',
|
||||
'<a href="http://www.youtube.com/watch?v=JghQgA2HMX8?d=200x200" >youtube\'s</a>'
|
||||
'<a href="http://www.youtube.com/watch?v=JghQgA2HMX8?d=200x200" >youtube\'s</a>',
|
||||
// Test a long URL under 4096 characters.
|
||||
$longurl
|
||||
);
|
||||
|
||||
//test for valid link
|
||||
@ -86,6 +97,9 @@ class filter_mediaplugin_testcase extends advanced_testcase {
|
||||
$this->assertNotEquals($text, $filter, $msg);
|
||||
}
|
||||
|
||||
$insertpoint = strrpos($longurl, 'http://');
|
||||
$longurl = substr_replace($longurl, 'http://pushover4096chars', $insertpoint, 0);
|
||||
|
||||
$invalidtexts = array(
|
||||
'<a class="_blanktarget">href="http://moodle.org/testfile/test.mp3"</a>',
|
||||
'<a>test test</a>',
|
||||
@ -101,7 +115,9 @@ class filter_mediaplugin_testcase extends advanced_testcase {
|
||||
'<href="http://moodle.org/testfile/test.avi">test</a>',
|
||||
'<abbr href="http://moodle.org/testfile/test.mp3">test mp3</abbr>',
|
||||
'<ahref="http://moodle.org/testfile/test.mp3">test mp3</a>',
|
||||
'<aclass="content" href="http://moodle.org/testfile/test.mp3">test mp3</a>'
|
||||
'<aclass="content" href="http://moodle.org/testfile/test.mp3">test mp3</a>',
|
||||
// Test a long URL over 4096 characters.
|
||||
$longurl
|
||||
);
|
||||
|
||||
//test for invalid link
|
||||
@ -110,5 +126,11 @@ class filter_mediaplugin_testcase extends advanced_testcase {
|
||||
$filter = $filterplugin->filter($text);
|
||||
$this->assertEquals($text, $filter, $msg);
|
||||
}
|
||||
|
||||
// Valid mediaurl followed by a longurl.
|
||||
$precededlongurl = '<a href="http://moodle.org/testfile/test.mp3">test.mp3</a>'. $longurl;
|
||||
$filter = $filterplugin->filter($precededlongurl);
|
||||
$this->assertEquals(1, substr_count($filter, 'M.util.add_audio_player'));
|
||||
$this->assertContains($longurl, $filter);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user