用PDO解决SQL注入问题
tl; dr:使用mysql重写数据库类以使用PDO来代替使用预处理语句,但从Kali运行sqlmap仍会从网站数据库中提取表。 怎么样?
更长的版本:
我注意到我们的一个网站在工作中存在SQL注入漏洞。 所以我开始研究它,从Kali运行sqlmap,然后从该网站的数据库中提取所有表。 看着它,网站使用的是旧的mysql api,经过一番研究,我决定改用PDO来利用预先准备好的语句来解决这个漏洞。 所以我主要重写了我们的数据库类并调用它来使用PDO。
昨晚我再次使用sqlmap进行测试,然后从该网站的数据库中提取所有表格。 我非常困惑,我能想到的唯一可能是它使用模拟预备语句而不是本地准备语句,所以我在创建PDO句柄时添加了选项以禁用模拟。 但显然这也没有什么区别。
问题:
我错过了什么? sqlmap仍然存在一个sql注入漏洞? 我如何有效解决这个问题?
码:
以下是调用代码:
public function Load($DbObject, $userName, $password) {
/* @var $DbObject DB */
if ($userName == "" || $password == "") {
$this->errMessage = "You must complete all fields.";
return (FALSE);
}
$fields = array("generic", "db", "fields");
$where_fields = array("userName", "password");
$where_values = array($userName, $password);
if ($DbObject->SelectQuery("db_table", $fields, $where_fields, $where_values)) {
if ($DbObject->RecordCount() == 1) {
$ret_val = TRUE;
$results = $DbObject->FetchResult();
for ($i = 0; $i < sizeof($fields); $i++) {
$this->{"$fields[$i]"} = $results[0][$i];
}
} else {
$this->errMessage = "<error_message>";
$ret_val = FALSE;
}
} else {
$this->errMessage = "<another_error_message>";
$ret_val = FALSE;
}
return ($ret_val);
}
以下是数据库类中的相关代码:
function SelectQuery($db_table, $db_fields, $where_fields = NULL, $where_values = NULL) {
$ret_val = TRUE;
$query = "SELECT " . implode(", ", $db_fields) . " FROM " . $db_table;
$numFields = count($where_fields);
if ($numFields > 0) {
$query .= " WHERE ";
$i = 1;
foreach ($where_fields as $field) {
$query .= "$field = ?";
if ($i < $numFields) {
$query .= " AND ";
}
$i++;
}
}
try {
$stmt = $this->db_handle->prepare($query);
if (is_null($where_fields)) {
$stmt->execute();
} else {
$stmt->execute($where_values);
}
$this->db_result = $stmt->fetchAll();
$this->db_numRecords = count($this->db_result);
} catch (PDOException $e) {
$ret_val = FALSE;
$this->db_errNumber = '<err_msg>' . $stmt->errorCode();
$this->db_errMessage = '<second_err_msg>' . $stmt->errorInfo();
$this->db_errDetailMessage = '<third_err_msg>' . $query;
}
return $ret_val;
}
function DB($type, $user, $pass, $host, $name) {
// set the default values for the DataBase class
$this->db_type = $type;
$this->db_user = $user;
$this->db_password = $pass;
$this->db_host = $host;
$this->db_name = $name;
$this->db_dsn = $type . ":host=" . $host . ";dbname=" . $name;
}
function OpenConnection() {
$returnValue = TRUE;
try {
$this->db_handle = new PDO($this->db_dsn, $this->db_user, $this->db_password, array(PDO::ATTR_EMULATE_PREPARES => FALSE));
$this->db_handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$returnValue = FALSE;
$this->db_errNumber = 002; /* ??? */
$this->db_errMessage = "<error_message>" . $e->getMessage();
}
return ($returnValue);
}
以下是用户登录时生成的sql语句:
SELECT generic, db, fields FROM db_table WHERE userName = ? AND password = ?
根据sqlmap,这是它使用的有效载荷:(redacted)
任何指导或建议,你可以提供有关使这个代码更强大的SQL注入漏洞非常感谢!
编辑 - 下面是关于我的设置的一些额外信息,可能相关也可能不相关:我们使用PHP 5.4.16和MariaDB 5.5.40。 从phpinfo()看来,我们使用的pdo_mysql驱动程序实际上是由MariaDB提供的,而不是使用mysqlnd。 这似乎是合适的,因为我们正在使用MariaDB而不是MySQL。 这完全可以影响使用本地准备的语句吗?
链接地址: http://www.djcxy.com/p/16759.html上一篇: Trouble addressing sql injection with PDO
下一篇: plain mysql prepare statement prevent injection attack?