- Patch #1265946 by klausi, tstoeckler, dereine, aspilicious: DoS against core using a large number of OR search query terms.

merge-requests/26/head
Dries 2011-12-21 09:31:28 -05:00
parent fdf48f2b99
commit 30d6b830cf
2 changed files with 39 additions and 0 deletions

View File

@ -122,6 +122,16 @@ class SearchQuery extends SelectQueryExtender {
*/
protected $multiply = array();
/**
* Whether or not search expressions were ignored.
*
* The maximum number of AND/OR combinations exceeded can be configured to
* avoid Denial-of-Service attacks. Expressions beyond the limit are ignored.
*
* @var boolean
*/
protected $expressionsIgnored = FALSE;
/**
* Sets up the search query expression.
*
@ -183,7 +193,17 @@ class SearchQuery extends SelectQueryExtender {
// Classify tokens.
$or = FALSE;
$warning = '';
$limit_combinations = variable_get('search_and_or_limit', 7);
// The first search expression does not count as AND.
$and_count = -1;
$or_count = 0;
foreach ($keywords as $match) {
if ($or_count && $and_count + $or_count >= $limit_combinations) {
// Ignore all further search expressions to prevent Denial-of-Service
// attacks using a high number of AND/OR combinations.
$this->expressionsIgnored = TRUE;
break;
}
$phrase = FALSE;
// Strip off phrase quotes.
if ($match[2]{0} == '"') {
@ -212,6 +232,7 @@ class SearchQuery extends SelectQueryExtender {
}
$this->keys['positive'][] = $last;
$or = TRUE;
$or_count++;
continue;
}
// AND operator: implied, so just ignore it.
@ -231,6 +252,7 @@ class SearchQuery extends SelectQueryExtender {
}
else {
$this->keys['positive'] = array_merge($this->keys['positive'], $words);
$and_count++;
}
}
$or = FALSE;
@ -323,6 +345,9 @@ class SearchQuery extends SelectQueryExtender {
form_set_error('keys', format_plural(variable_get('minimum_word_size', 3), 'You must include at least one positive keyword with 1 character or more.', 'You must include at least one positive keyword with @count characters or more.'));
return FALSE;
}
if ($this->expressionsIgnored) {
drupal_set_message(t('Your search used too many AND/OR expressions. Only the first @count terms were included in this search.', array('@count' => variable_get('search_and_or_limit', 7))), 'warning');
}
$this->executedFirstPass = TRUE;
if (!empty($this->words)) {

View File

@ -290,6 +290,20 @@ class SearchPageText extends DrupalWebTestCase {
$this->drupalGet('search/node/' . $arg);
$input = $this->xpath("//input[@id='edit-keys' and @value='{$arg}']");
$this->assertFalse(empty($input), 'Search keys with a / are correctly set as the default value in the search box.');
// Test a search input exceeding the limit of AND/OR combinations to test
// the Denial-of-Service protection.
$limit = variable_get('search_and_or_limit', 7);
$keys = array();
for ($i = 0; $i < $limit + 1; $i++) {
$keys[] = $this->randomName(3);
if ($i % 2 == 0) {
$keys[] = 'OR';
}
}
$edit['keys'] = implode(' ', $keys);
$this->drupalPost('search/node', $edit, t('Search'));
$this->assertRaw(t('Your search used too many AND/OR expressions. Only the first @count terms were included in this search.', array('@count' => $limit)));
}
}