【问题标题】:Is this a insecure way to use prepared statements in a php class?这是在 php 类中使用准备好的语句的不安全方式吗?
【发布时间】:2019-02-07 11:54:19
【问题描述】:

我用函数 query() 创建了这个类:

这个函数使得使用准备好的语句变得非常容易。 但是

  • 安全吗?
  • 这样使用它更有意义吗?

我已经用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>";
}

【问题讨论】:

  • 您希望我们回答哪个问题;标题中的那个,还是正文中的那个?
  • 只是……为什么要这样做?为什么不提供一个接受参数化查询的查询方法以及要绑定的对象数组?
  • 这属于代码审查网站。
  • @SilvanFux Make it even sense to use it like that? - 没有。
  • 这是我所见过的最复杂的代码,无法实现任何目标

标签: php mysql mysqli prepared-statement


【解决方案1】:

在您已经将值插入其中之后,您无法根据定义“准备”/“清理”/理解查询。

$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

遵循的任何代码怎么可能理解这个查询应该做什么和它现在实际做什么之间的区别?这不可以。通过值注入已经改变了含义。事后没有办法解决这个问题。

【讨论】:

  • 是的,我看到了问题。
  • 完全更新了功能。新的应该是安全的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-28
  • 1970-01-01
相关资源
最近更新 更多