Commit 463a710b authored by catch's avatar catch
Browse files

Issue #1265946 by klausi, dereine, tstoeckler, aspilicious: Fixed DoS against...

Issue #1265946 by klausi, dereine, tstoeckler, aspilicious: Fixed DoS against core using a large number of OR search query terms.
parent 8d4f0916
......@@ -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 @@ protected function parseSearchExpression() {
// 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 @@ protected function parseSearchExpression() {
}
$this->keys['positive'][] = $last;
$or = TRUE;
$or_count++;
continue;
}
// AND operator: implied, so just ignore it.
......@@ -231,6 +252,7 @@ protected function parseSearchExpression() {
}
else {
$this->keys['positive'] = array_merge($this->keys['positive'], $words);
$and_count++;
}
}
$or = FALSE;
......@@ -323,6 +345,9 @@ public function executeFirstPass() {
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)) {
......
......@@ -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)));
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment