用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?