这是在 php class 中使用准备好的语句的不安全方式吗?

Is this a insecure way to use prepared statements in a php class?

我用函数 query():

做了这个 Class

这个功能让预处理语句的使用变得非常简单。 但是

我已经用 sqlmap 测试过了,看起来不错。

该函数基本上将正常的 SELECT 字符串拆分为多个较小的字符串以检测输入值。 它保存输入值和字符串本身。 字符串本身将被替换为 ?。 比正常的准备功能取代了?再次使用输入值。

    class dbcon
    {   
        public $con;

        public function __construct()
        {
            $this->con = new mysqli( $host, $username, $password, $dbname );
        }


    public function query( $query )
    {   
        //selcet
        if( strpos( $query, "SELECT" ) !== false )
        {   
            $types = ""; $to_replace = []; $values = [];

            $query = explode( "WHERE", $query );
            $query_where = explode( "ORDER BY", $query[ '1' ] );

            $query_where[ '0' ];

            if( isset( $query_where[ '1' ] ) ) 
            { 
                $ORDERBY = explode("LIMIT", $query_where[ '1' ]); 
            }
            if( isset( $ORDERBY[ '1' ] ) )
            {
                $LIMIT = $ORDERBY[ '1' ];
            }

            $SELECT = $query[ '0' ];

            $where = str_replace( array( "(", ")", "[", "]" ), "", $query_where[ '0' ] );
            $where = str_replace( array( "AND", "OR", "and", "or" ), "-|-", $where );
            $where = explode( "-|-", $where );

            for ($i=0; $i < count($where); $i++) {
                $for_where = str_replace( array( "!=", "<=", ">=", "=", "<>", ">", "<", "IS", "NOT LIKE", "LIKE" ), "#|#", $where[ $i ] );
                $for_where = explode( "#|#", $for_where );

                $value = trim( $for_where[ '1' ] );
                if( substr_count($value, "AND") <= 0 AND substr_count($value, "OR") <= 0 )
                {
                    $value = "'?'";
                }

                $to_replace[] = $value;
                $value_num = "values".$i;
                $$value_num = $value;
                $values[] = &$$value_num;

                $types .= "s";
            }
            $WHERE = str_replace( $to_replace , " ? ", $query_where[ '0' ] );

            $prepare = $SELECT . " WHERE " . $WHERE;
            if ( isset( $ORDERBY ) )
            {
                $prepare .= " ORDER BY " . $ORDERBY[ '0' ];
            }
            if ( isset( $LIMIT ) ){
                $prepare .= " LIMIT " . $LIMIT;
            }

            $stmt = $this->con->prepare( $prepare );
            //$stmt->bind_param($types, $values['0'],$values['1']);
            call_user_func_array( array( $stmt, "bind_param" ), array_merge( array( $types ), $values ) );

            $stmt->execute();
                return $stmt->get_result();
            $stmt->close();
        }
    }
}

$db = new dbcon();

调用函数:

$id = $_GET[ 'id' ];
$my_query = $db->query("SELECT * FROM Users WHERE ID = '$id' ORDER BY created DESC");

while($row = $my_query->fetch_array()){ 
    echo $row['NAME']."<br>";   
}

更新:

旧功能没有多大意义,而且一点也不安全。这应该仍然是一个简单的方法,但更好。

public function query( $query, $types, $query_values )
{   
    $values = [];


for ($i=0; $i < count($query_values); $i++) {
    $value_num = "values".$i;
    $$value_num = $query_values[ $i ];
    $values[] = &$$value_num;
}

$stmt = $this->con->prepare( $query );
call_user_func_array( array( $stmt, "bind_param" ), array_merge( array( $types ), $values ) );

$stmt->execute();
    return $stmt->get_result();
    $stmt->close();
}

调用函数

$query  = "SELECT * FROM _Users WHERE ID = ? ORDER BY created ASC";
$my_query = $db->query( $query, "s", array( $id ) );

while($row = $my_query->fetch_array()){
    echo $row['title']."<br>";
}

根据定义,您无法"prepare"/"sanitise"/理解已经将值插入其中的查询。

$my_query = $db->query("SELECT * FROM Users WHERE ID = '$id' ORDER BY created DESC");

那么如果有人尝试 SQL 注入会发生什么?例如:$id = "foo' OR '1' = '1":

SELECT * FROM Users WHERE ID = 'foo' OR '1' = '1' ORDER BY created DESC

后面的任何代码怎么可能理解这个查询应该做的和它是什么之间的区别 =]实际上现在在做什么?这不可以。含义已经通过价值注入改变了。事后无法解决此问题。