I'm using SensioLabsInsight to profile any vulnerabilities in my code.
I've received several errors for possible sql injection, and it recommends using parameter binding with PDO. This is fine since I'm already using PDO for my db driver.
Right now my model is passed a $data
array and then checks for specific values in the array in order to add to the sql query if present, like so:
public function getDownloads($data = array()) {
$sql = "
SELECT *
FROM {$this->db->prefix}download d
LEFT JOIN {$this->db->prefix}download_description dd
ON (d.download_id = dd.download_id)
WHERE dd.language_id = '" . (int)$this->config->get('config_language_id') . "'";
if (!empty($data['filter_name'])) {
$sql .= " AND dd.name LIKE '" . $this->db->escape($data['filter_name']) . "%'";
}
$sort_data = array(
'dd.name',
'd.remaining'
);
if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
$sql .= " ORDER BY " . $data['sort'];
} else {
$sql .= " ORDER BY dd.name";
}
if (isset($data['order']) && ($data['order'] == 'DESC')) {
$sql .= " DESC";
} else {
$sql .= " ASC";
}
if (isset($data['start']) || isset($data['limit'])) {
if ($data['start'] < 0) {
$data['start'] = 0;
}
if ($data['limit'] < 1) {
$data['limit'] = 20;
}
$sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit'];
}
$query = $this->db->query($sql);
return $query->rows;
}
The error referenced from the SensioLabsInsight analysis references only the $data['sort'] clause as being a possible injection point.
My question is, do I need to test for $data array presence when creating a prepare statement, or will it simply return null if the array value is empty.
My proposed new query with parameter binding would look like so:
public function getDownloads($data = array()) {
$sql = "
SELECT *
FROM {$this->db->prefix}download d
LEFT JOIN {$this->db->prefix}download_description dd
ON (d.download_id = dd.download_id)
WHERE dd.language_id = '" . (int)$this->config->get('config_language_id') . "'";
if (!empty($data['filter_name'])) {
$sql .= " AND dd.name LIKE :filter_name%";
}
$sort_data = array(
'dd.name',
'd.remaining'
);
if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
$sql .= " ORDER BY :sort";
} else {
$sql .= " ORDER BY dd.name";
}
if (isset($data['order']) && ($data['order'] == 'DESC')) {
$sql .= " DESC";
} else {
$sql .= " ASC";
}
if (isset($data['start']) || isset($data['limit'])) {
if ($data['start'] < 0) {
$data['start'] = 0;
}
if ($data['limit'] < 1) {
$data['limit'] = 20;
}
$sql .= " LIMIT :start, :limit";
}
$this->db->prepare($sql);
$this->db->bindParam(':filter_name', $data['filter_name']);
$this->db->bindParam(':sort', $data['sort']);
$this->db->bindParam(':start', $data['start'], PDO::PARAM_INT);
$this->db->bindParam(':limit', $data['limit'], PDO::PARAM_INT);
$query = $this->db->execute();
return $query->rows;
}
Will this work as is, or do the parameter bindings need to be moved within the if/else conditionals?