Skip to content
This repository was archived by the owner on Oct 2, 2019. It is now read-only.

Commit b1c71dd

Browse files
ezimuelweierophinney
authored andcommitted
Fixed SQL Injection in order and group
1 parent e368bc5 commit b1c71dd

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

library/Zend/Db/Select.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,23 @@ class Zend_Db_Select
8484
const REGEX_COLUMN_EXPR = '/^([\w]*\s*\(([^\(\)]|(?1))*\))$/';
8585
const REGEX_COLUMN_EXPR_ORDER = '/^([\w]+\s*\(([^\(\)]|(?1))*\))$/';
8686
const REGEX_COLUMN_EXPR_GROUP = '/^([\w]+\s*\(([^\(\)]|(?1))*\))$/';
87+
88+
// @see http://stackoverflow.com/a/13823184/2028814
89+
const REGEX_SQL_COMMENTS = '@
90+
(([\'"]).*?[^\\\]\2) # $1 : Skip single & double quoted expressions
91+
|( # $3 : Match comments
92+
(?:\#|--).*?$ # - Single line comments
93+
| # - Multi line (nested) comments
94+
/\* # . comment open marker
95+
(?: [^/*] # . non comment-marker characters
96+
|/(?!\*) # . ! not a comment open
97+
|\*(?!/) # . ! not a comment close
98+
|(?R) # . recursive case
99+
)* # . repeat eventually
100+
\*\/ # . comment close marker
101+
)\s* # Trim after comments
102+
|(?<=;)\s+ # Trim after semi-colon
103+
@msx';
87104

88105
/**
89106
* Bind variables for query
@@ -513,7 +530,9 @@ public function group($spec)
513530
}
514531

515532
foreach ($spec as $val) {
516-
if (preg_match(self::REGEX_COLUMN_EXPR_GROUP, (string) $val)) {
533+
// Remove comments from SQL statement
534+
$noComments = preg_replace(self::REGEX_SQL_COMMENTS, '$1', (string) $val);
535+
if (preg_match(self::REGEX_COLUMN_EXPR_GROUP, $noComments)) {
517536
$val = new Zend_Db_Expr($val);
518537
}
519538
$this->_parts[self::GROUP][] = $val;
@@ -605,7 +624,9 @@ public function order($spec)
605624
$val = trim($matches[1]);
606625
$direction = $matches[2];
607626
}
608-
if (preg_match(self::REGEX_COLUMN_EXPR_ORDER, (string) $val)) {
627+
// Remove comments from SQL statement
628+
$noComments = preg_replace(self::REGEX_SQL_COMMENTS, '$1', (string) $val);
629+
if (preg_match(self::REGEX_COLUMN_EXPR_ORDER, $noComments)) {
609630
$val = new Zend_Db_Expr($val);
610631
}
611632
$this->_parts[self::ORDER][] = array($val, $direction);

tests/Zend/Db/Select/StaticTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,10 @@ public function testSqlInjectionWithOrder()
838838
$select = $this->_db->select();
839839
$select->from('p')->order("MD5(\";(\");DELETE FROM p2; SELECT 1 #)");
840840
$this->assertEquals('SELECT "p".* FROM "p" ORDER BY "MD5("";("");DELETE FROM p2; SELECT 1 #)" ASC', $select->assemble());
841+
842+
$select = $this->_db->select();
843+
$select->from('p')->order("MD5(\"a(\");DELETE FROM p2; #)");
844+
$this->assertEquals('SELECT "p".* FROM "p" ORDER BY "MD5(""a("");DELETE FROM p2; #)" ASC', $select->assemble());
841845
}
842846

843847
public function testSqlInjectionWithGroup()
@@ -853,6 +857,10 @@ public function testSqlInjectionWithGroup()
853857
$select = $this->_db->select();
854858
$select->from('p')->group("MD5(\";(\");DELETE FROM p2; SELECT 1 #)");
855859
$this->assertEquals('SELECT "p".* FROM "p" GROUP BY "MD5("";("");DELETE FROM p2; SELECT 1 #)"', $select->assemble());
860+
861+
$select = $this->_db->select();
862+
$select->from('p')->group("MD5(\"a(\");DELETE FROM p2; #)");
863+
$this->assertEquals('SELECT "p".* FROM "p" GROUP BY "MD5(""a("");DELETE FROM p2; #)"', $select->assemble());
856864
}
857865

858866
public function testSqlInjectionInColumn()

0 commit comments

Comments
 (0)