【问题标题】:Concatenated dynamic PDO query safe from injection without bindparam连接动态 PDO 查询,无需绑定参数即可安全注入
【发布时间】:2015-03-08 03:20:53
【问题描述】:

我有一个页面生成一个记录列表,我想通过多种可能性过滤或缩小范围。因此,我正在考虑将可能的 "AND" 语句添加到 SQL 查询中。用户生成的数据不会进入查询,除了传递给查询的 LIMIT 部分的分页。

我的问题:

  1. 因为我没有使用 bindParam,所以在 LIMIT 之后是否可以进行注入?

    $start_record = $_GET['page'];
    $ids = array('pid_b', 'pid_l', 'pid_g' );
    $qMarks = str_repeat('?,', count($ids) - 1) . '?';
    
    // THIS MY CONDITION FOR TESTING PURPOSES ONLY
    $testVar = 1;
    
    // NOW WE BUILD THE QUERY
    $sqlQuery = "SELECT * FROM inventory_tbl ";
    $sqlQuery .= "WHERE `consignor_record_id` IN ($qMarks) ';
    $sqlQuery .= ($testVar == 1 ? " AND `inventory_status` <> 'active' " : "");
    $sqlQuery .= "ORDER BY `created_date` DESC LIMIT $start_record, 50 ;";
    
    $productSearch = $dbh->prepare( $sqlQuery );
    

【问题讨论】:

  • 我不相信它除了你所说的LIMIT。我很好奇@cmorrissey 是怎么想的。
  • 本着教育精神,介意解释一下吗?
  • @JonathanKuhn,他的问题是在LIMIT 之后是否可以注射,绝对是,他并没有说它是开放的
  • 啊,是的。我读错了。谢谢。
  • @JonathanKuhn,详细的评论应该是一个答案。它足以回答这个问题。

标签: php mysql security pdo


【解决方案1】:

此查询不能安全注入。你可以通过 $_GET['page'] 注入。

【讨论】:

    【解决方案2】:

    那么是的,它对sql注入开放。一个主要的 sql 注入问题是通过联合将多个查询连接在一起。如果我知道inventory_tbl 有多少列以及users 表之类的其他名称,我可以发送一个页面获取值为0 UNION ALL SELECT col1,col2 FROM USERS --,它实际上会从inventory 表中选择零行并从users 表中选择所有行或类似的。或者,如果这不起作用,请发送一个子查询以获取执行其他代码的限制。甚至分号来结束选择和除第一个之外要执行的任何其他查询。

    【讨论】:

    • 感谢您的解释!有没有办法在 PDO 中防止它?
    • 由于 limit 接受一个数字,您可以检查 is_numeric 是否为 int。
    【解决方案3】:

    来自 PDO 维基

    当处于仿真模式(默认开启)时,PDO 替代 具有实际数据的占位符。并使用“惰性”绑定(使用数组 execute()),PDO 将每个参数视为一个字符串。结果, 准备 LIMIT ?,?查询变为 LIMIT '10', '10' 无效 导致查询失败的语法。

    解决方案是关闭仿真(因为 MySQL 可以对所有 占位符正确)。

    $start_record =  1;//$_GET['page'];
    $ids = array('pid_b', 'pid_l', 'pid_g' );
    // THIS MY CONDITION FOR TESTING PURPOSES ONLY
    $testVar = 1;
    //Set up parameters for lazy binding
    $params =$ids;//Fill array with ids
    array_push($params,$testVar);
    array_push($params,$start_record);
    $qMarks = str_repeat('?,', count($ids) - 1) . '?';
    // NOW WE BUILD THE QUERY
    $sqlQuery = "SELECT * FROM inventory_tbl ";
    $sqlQuery .= "WHERE `consignor_record_id` IN ($qMarks) ";
    $sqlQuery .= "AND $testVar == ? AND `inventory_status` <> 'active' " ;
    $sqlQuery .= "ORDER BY `created_date` DESC LIMIT ?, 50 ;";
    //To turn emulation off, one can run this code (or set in a connection options array):
    $conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
    $productSearch = $dbh->prepare($sqlQuery );
    $productSearch->execute($params);
    //Remove echos after testing
    echo $sqlQuery;
    echo "<br>";
    var_dump($params);
    

    结果

    SELECT * FROM inventory_tbl WHERE `consignor_record_id` IN (?,?,?) AND 1 == ? AND `inventory_status` <> 'active' ORDER BY `created_date` DESC LIMIT ?, 50 ;
    

    延迟绑定的参数

      array(5) { [0]=> string(5) "pid_b" [1]=> string(5) "pid_l" [2]=> string(5) "pid_g" [3]=> int(1) [4]=> int(1) } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-07
      • 2019-09-15
      • 2017-09-28
      • 2017-04-17
      • 2013-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多