Parcourir la source

Merge branch 'security/zf2016-03'

Resolves ZF2016-03 advisory.
Matthew Weier O'Phinney il y a 9 ans
Parent
commit
73cb94e99d
2 fichiers modifiés avec 31 ajouts et 2 suppressions
  1. 23 2
      library/Zend/Db/Select.php
  2. 8 0
      tests/Zend/Db/Select/StaticTest.php

+ 23 - 2
library/Zend/Db/Select.php

@@ -84,6 +84,23 @@ class Zend_Db_Select
     const REGEX_COLUMN_EXPR       = '/^([\w]*\s*\(([^\(\)]|(?1))*\))$/';
     const REGEX_COLUMN_EXPR_ORDER = '/^([\w]+\s*\(([^\(\)]|(?1))*\))$/';
     const REGEX_COLUMN_EXPR_GROUP = '/^([\w]+\s*\(([^\(\)]|(?1))*\))$/';
+    
+    // @see http://stackoverflow.com/a/13823184/2028814
+    const REGEX_SQL_COMMENTS      = '@
+    (([\'"]).*?[^\\\]\2) # $1 : Skip single & double quoted expressions
+    |(                   # $3 : Match comments
+        (?:\#|--).*?$    # - Single line comments
+        |                # - Multi line (nested) comments
+         /\*             #   . comment open marker
+            (?: [^/*]    #   . non comment-marker characters
+                |/(?!\*) #   . ! not a comment open
+                |\*(?!/) #   . ! not a comment close
+                |(?R)    #   . recursive case
+            )*           #   . repeat eventually
+        \*\/             #   . comment close marker
+    )\s*                 # Trim after comments
+    |(?<=;)\s+           # Trim after semi-colon
+    @msx';
 
     /**
      * Bind variables for query
@@ -513,7 +530,9 @@ class Zend_Db_Select
         }
 
         foreach ($spec as $val) {
-            if (preg_match(self::REGEX_COLUMN_EXPR_GROUP, (string) $val)) {
+            // Remove comments from SQL statement
+            $noComments = preg_replace(self::REGEX_SQL_COMMENTS, '$1', (string) $val);
+            if (preg_match(self::REGEX_COLUMN_EXPR_GROUP, $noComments)) {
                 $val = new Zend_Db_Expr($val);
             }
             $this->_parts[self::GROUP][] = $val;
@@ -605,7 +624,9 @@ class Zend_Db_Select
                     $val = trim($matches[1]);
                     $direction = $matches[2];
                 }
-                if (preg_match(self::REGEX_COLUMN_EXPR_ORDER, (string) $val)) {
+                // Remove comments from SQL statement
+                $noComments = preg_replace(self::REGEX_SQL_COMMENTS, '$1', (string) $val);
+                if (preg_match(self::REGEX_COLUMN_EXPR_ORDER, $noComments)) {
                     $val = new Zend_Db_Expr($val);
                 }
                 $this->_parts[self::ORDER][] = array($val, $direction);

+ 8 - 0
tests/Zend/Db/Select/StaticTest.php

@@ -838,6 +838,10 @@ class Zend_Db_Select_StaticTest extends Zend_Db_Select_TestCommon
         $select = $this->_db->select();
         $select->from('p')->order("MD5(\";(\");DELETE FROM p2; SELECT 1 #)");
         $this->assertEquals('SELECT "p".* FROM "p" ORDER BY "MD5("";("");DELETE FROM p2; SELECT 1 #)" ASC', $select->assemble());
+
+        $select = $this->_db->select();
+        $select->from('p')->order("MD5(\"a(\");DELETE FROM p2; #)");
+        $this->assertEquals('SELECT "p".* FROM "p" ORDER BY "MD5(""a("");DELETE FROM p2; #)" ASC', $select->assemble());
     }
 
     public function testSqlInjectionWithGroup()
@@ -853,6 +857,10 @@ class Zend_Db_Select_StaticTest extends Zend_Db_Select_TestCommon
         $select = $this->_db->select();
         $select->from('p')->group("MD5(\";(\");DELETE FROM p2; SELECT 1 #)");
         $this->assertEquals('SELECT "p".* FROM "p" GROUP BY "MD5("";("");DELETE FROM p2; SELECT 1 #)"', $select->assemble());
+
+        $select = $this->_db->select();
+        $select->from('p')->group("MD5(\"a(\");DELETE FROM p2; #)");
+        $this->assertEquals('SELECT "p".* FROM "p" GROUP BY "MD5(""a("");DELETE FROM p2; #)"', $select->assemble());
     }
 
     public function testSqlInjectionInColumn()