2
0
forked from Wavyzz/dolibarr

Fix protect use of sanitize to make sql injection

This commit is contained in:
ldestailleur
2025-03-06 03:29:54 +01:00
parent ca9763afc1
commit caead5de9f
5 changed files with 51 additions and 9 deletions

View File

@@ -868,7 +868,7 @@ if ($search_status != '-1' && $search_status != '') {
$sql .= " AND f.fk_statut = 3"; // abandoned
}
} else {
$sql .= " AND f.fk_statut IN (".$db->sanitize($db->escape($search_status)).")"; // When search_status is '1,2' for example
$sql .= " AND f.fk_statut IN (".$db->sanitize($search_status).")"; // When search_status is '1,2' for example
}
}

View File

@@ -177,7 +177,8 @@ abstract class DoliDB implements Database
* Sanitize a string for SQL forging
*
* @param string $stringtosanitize String to sanitize
* @param int $allowsimplequote 1=Allow simple quotes in string. When string is used as a list of SQL string ('aa', 'bb', ...)
* @param int $allowsimplequote 1=Allow simple quotes in string around val separated by "," but only when string is used as a list of SQL string "'aa', 'bb', 'cc', ..."). Can be used for IN ...
* 2=Allow all simple quotes. If you use this value, the return MUST be escaped to forge SQL strings.
* @param int $allowsequals 1=Allow equals sign
* @param int $allowsspace 1=Allow space char
* @param int $allowschars 1=Allow a-z chars
@@ -185,7 +186,25 @@ abstract class DoliDB implements Database
*/
public function sanitize($stringtosanitize, $allowsimplequote = 0, $allowsequals = 0, $allowsspace = 0, $allowschars = 1)
{
return preg_replace('/[^0-9_\-\.,'.($allowschars ? 'a-z' : '').($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').($allowsspace ? ' ' : '').']/i', '', $stringtosanitize);
//$result = preg_replace('/[^0-9_\-\.,'.($allowschars ? '\p{L}' : '').($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').($allowsspace ? ' ' : '').']/ui', '', $stringtosanitize);
$result = preg_replace('/[^0-9_\-\.,'.($allowschars ? 'a-z' : '').($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').($allowsspace ? ' ' : '').']/i', '', $stringtosanitize);
if ($allowsimplequote == 1) {
// Remove all quotes that are inside a string and not around
$tmpchars = explode(',', $result);
$newstringarray = array();
foreach ($tmpchars as $tmpchar) {
$reg = array();
if (preg_match('/^\'(.*)\'$/', $tmpchar, $reg)) {
$newstringarray[] = "'".str_replace("'", "", $reg[1])."'";
} else {
$newstringarray[] = str_replace("'", "", $tmpchar);
}
}
$result = join(',', $newstringarray);
}
return $result;
}
/**

View File

@@ -14424,7 +14424,7 @@ function dolForgeSQLCriteriaCallback($matches)
$reg = array();
$tmpelem = trim($tmpelem);
if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
$tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1, 1))."'";
$tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 2, 1, 1, 1))."'";
} elseif (ctype_digit((string) $tmpelem)) { // if only 0-9 chars, no .
$tmpelemarray[$tmpkey] = (int) $tmpelem;
} elseif (is_numeric((string) $tmpelem)) { // it can be a float with a .

View File

@@ -162,7 +162,7 @@ class TaskStats extends Stats
$sqlwhere[] = " t.datec BETWEEN '".$this->db->idate(dol_get_first_day($this->year, $this->month))."' AND '".$this->db->idate(dol_get_last_day($this->year, $this->month))."'";
}
if (!empty($this->priority)) {
$sqlwhere[] = " t.priority IN (".$this->db->sanitize((string) $this->priority, 1).")";
$sqlwhere[] = " t.priority = ".((int) $this->priority);
}
if (count($sqlwhere) > 0) {

View File

@@ -1925,13 +1925,36 @@ class FunctionsLibTest extends CommonClassTest
*/
public function testNaturalSearch()
{
global $db;
$s = natural_search("t.field", "abc def");
$this->assertEquals($s, " AND (t.field LIKE '%abc%' AND t.field LIKE '%def%')");
$this->assertEquals(" AND (t.field LIKE '%abc%' AND t.field LIKE '%def%')", $s);
$s = natural_search("t.field", "'abc def' ghi");
$this->assertEquals($s, " AND (t.field LIKE '%abc def%' AND t.field LIKE '%ghi%')");
$this->assertEquals(" AND (t.field LIKE '%abc def%' AND t.field LIKE '%ghi%')", $s);
$s = natural_search("t.field", "abc def,ghi", 3);
$this->assertEquals($s, " AND (t.field IN ('abc def','ghi'))");
$s = natural_search("t.field", "abc def,ghi", 3); // mode 3 is to provide a list of string separated with coma
$this->assertEquals(" AND (t.field IN ('abc def','ghi'))", $s);
$s = natural_search("t.field", "'ab\'c' def','ghi', 'jkl'", 3); // mode 3 is to provide a list of string separated with coma
$this->assertEquals(" AND (t.field IN ('abc def','ghi','jkl'))", $s);
$s = natural_search("t.field", "a,b", 3); // mode 3 is to provide a list of string separated with coma
$this->assertEquals(" AND (t.field IN ('a','b'))", $s);
$s = natural_search("t.field", "A'@%B", 3); // mode 3 is to provide a list of string separated with coma
$this->assertEquals(" AND (t.field IN ('AB'))", $s);
/*
$s = $db->sanitize("a,b", 1);
var_dump($s);
$s = $db->sanitize("'a',b", 1);
var_dump($s);
$s = $db->sanitize("'a'b',c", 1);
var_dump($s);
*/
//$s = natural_search("t.field", "KØB", 3); // mode 3 is to provide a list of string separated with coma
//$this->assertEquals(" AND (t.field IN ('KØB'))", $s);
}
}