diff --git a/core/modules/search/search.extender.inc b/core/modules/search/search.extender.inc
index b7af4d0..e4589ae 100644
--- a/core/modules/search/search.extender.inc
+++ b/core/modules/search/search.extender.inc
@@ -123,6 +123,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.
    *
    * @param $query
@@ -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 +230,7 @@ class SearchQuery extends SelectQueryExtender {
         }
         $this->keys['positive'][] = $last;
         $or = TRUE;
+        $or_count++;
         continue;
       }
       // AND operator: implied, so just ignore it.
@@ -231,6 +250,7 @@ class SearchQuery extends SelectQueryExtender {
         }
         else {
           $this->keys['positive'] = array_merge($this->keys['positive'], $words);
+          $and_count++;
         }
       }
       $or = FALSE;
@@ -323,6 +343,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)) {
diff --git a/core/modules/search/search.test b/core/modules/search/search.test
index 3ea089c..3989c17 100644
--- a/core/modules/search/search.test
+++ b/core/modules/search/search.test
@@ -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 DoS 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)));
   }
 }
 
