【问题标题】:avoiding MySQL injections with the Zend_Db class避免使用 Zend_Db 类进行 SQL 注入
【发布时间】:2010-11-01 18:42:34
【问题描述】:

我目前使用 Zend_Db 来管理我的查询。 我已经编写了执行如下查询的代码:

$handle->select()->from('user_id')
                   ->where('first_name=?', $id)
                   ->where('last_name=?', $lname)

假设 Zend_Db 会,我在没有清理输入的情况下完成了这项工作。 Zend 会这样做吗?

另一个问题: Zend_Db 是否清理 insert('table', $data)update 查询?

谢谢。

【问题讨论】:

    标签: php mysql zend-framework zend-db-table


    【解决方案1】:

    我在 Zend Framework 中编写了很多用于数据库参数和引用的代码,而我是该项目的团队负责人(最高版本 1.0)。

    我尝试尽可能鼓励最佳做法,但我必须在易用性和易用性之间取得平衡。

    请注意,您始终可以检查 Zend_Db_Select 对象的字符串值,以了解它是如何决定引用的。

    print $select; // invokes __toString() method
    

    您还可以使用Zend_Db_Profiler 来检查Zend_Db 代表您运行的SQL。

    $db->getProfiler()->setEnabled(true);
    $db->update( ... );
    print $db->getProfiler()->getLastQueryProfile()->getQuery(); 
    print_r $db->getProfiler()->getLastQueryProfile()->getQueryParams(); 
    $db->getProfiler()->setEnabled(false);
    

    以下是您具体问题的一些答案:

    • Zend_Db_Select::where('last_name=?', $lname)

      值被适当地引用。尽管“?”看起来像一个参数占位符,但在此方法中,参数实际上被适当地引用和插值。所以它不是一个真正的查询参数。事实上,以下两条语句产生的查询与上述用法完全相同:

      $select->where( $db->quoteInto('last_name=?', $lname) );
      $select->where( 'last_name=' . $db->quote($lname) );
      

      但是,如果您传递的参数是Zend_Db_Expr 类型的对象,则它不会被引用。您应对 SQL 注入风险负责,因为它是逐字插入的,以支持表达式值:

      $select->where('last_modified < ?', new Zend_Db_Expr('NOW()'))
      

      该表达式中需要引用或分隔的任何其他部分均由您负责。例如,如果您将任何 PHP 变量插入到表达式中,则安全是您的责任。如果您的列名是 SQL 关键字,您需要自己用quoteIdentifier() 分隔它们。示例:

      $select->where($db->quoteIdentifier('order').'=?', $myVariable)
      
    • Zend_Db_Adapter_Abstract::insert( array('colname' =&gt; 'value') )

      表名和列名是分隔的,除非你关闭AUTO_QUOTE_IDENTIFIERS

      值被参数化为真正的查询参数(未插值)。除非该值是 Zend_Db_Expr 对象,在这种情况下,它是逐字插入的,因此您可以插入表达式或 NULL 或其他任何内容。

    • Zend_Db_Adapter_Abstract::update( array('colname' =&gt; 'value'), $where )

      表名和列名是分隔的,除非你关闭AUTO_QUOTE_IDENTIFIERS

      值是参数化的,除非它们是Zend_Db_Expr 对象,如insert() 方法。

      $where 参数根本没有被过滤,因此您应对该参数中的任何 SQL 注入风险负责。您可以使用quoteInto() 方法来帮助使引用更方便。

    【讨论】:

    • 很好的答案,比尔,以及一个很棒的组件:)
    • 如果您在TableGateway 的实例上使用insert() 函数,则会自动为您完成具有保留名称的列的转义,如上面第二个项目符号所述。如果您手动转义它(即(SQL Server)array ( [from] =&gt; 1 )); 它会产生一个数据库错误,指出'[from]' 是一个无效的列名。该列可能已被转义两次为[[from]]
    【解决方案2】:

    关于这一点,当值为 NULL 时,您可以获得无效查询

    $value = NULL;
    $select->where('prop=?', $value);
    

    结果:SQL 错误

    【讨论】:

    • 在 SQL 中,无论如何都不能使用 = 运算符与 NULL 进行比较。
    • 我的例子不是关于 NULL 值,我试图证明在某些情况下你需要检查/转换类型的值来传递 sql-query 构建函数,这是在讨论的上下文中
    【解决方案3】:

    过滤输入总是好的,因为它很可能会进入数据库以外的其他地方,并且您至少希望数据库中的数据在某个级别上是健全的。

    • Zend_Filter_Input 在路上
    • Prepared 语句(如果不在 Prepared 中,则为 quoteInto)
    • 退出时转义过滤器(htmlentities 等)。

    【讨论】:

      【解决方案4】:

      默认情况下,当您在 SQL 查询中使用值绑定时,如下所示:

      where('first_name=?', $id);
      

      Zend_Db 使用适当的引用值来防止 SQL 注入。尽管强烈建议(通过书籍、文章、手册和自我体验)清理/过滤用户输入。 Zend_Filter 会很有帮助。

      【讨论】:

        【解决方案5】:

        当你在其他地方需要它时(比如加入)或者你不确定它是否会被转义,那么你总是可以使用$this-&gt;getAdapter()-&gt;quoteInto('type = ?',1);

        【讨论】:

          【解决方案6】:

          应该让你感到安全的一点是? where 子句中的标记。这些是参数,由数据库系统安全地替换为第二个参数。

          【讨论】:

          • 是的,我的意思是与 Zend_Db 方法调用有关
          【解决方案7】:

          是的。见http://framework.zend.com/manual/en/zend.db.select.html。别担心。你怀疑是对的。

          【讨论】:

            猜你喜欢
            • 2016-09-16
            • 1970-01-01
            • 2017-12-02
            • 1970-01-01
            • 2016-12-09
            • 2019-06-26
            • 1970-01-01
            • 1970-01-01
            • 2021-09-03
            相关资源
            最近更新 更多