这个查询是不是受到 sql 注入的保护? [复制]

Posted

技术标签:

【中文标题】这个查询是不是受到 sql 注入的保护? [复制]【英文标题】:Is this query secured from sql injection? [duplicate]这个查询是否受到 sql 注入的保护? [复制] 【发布时间】:2019-07-09 16:45:02 【问题描述】:

我想知道这个 sql 查询是否受到 sql-injection 的保护,是否可以,或者我应该修改一些东西。

我尝试从 GET 绑定 id,如果一切正常,我会使用带有该 id 的实际查询。

if(isset($_GET['id']) && $_GET['id'] != null) 
  $id = $_GET['id'];

  $stmt = $mysqli->prepare('SELECT id FROM maps WHERE id = ?');
  $stmt->bind_param('i', $id);

  $stmt->execute();

  $result = $stmt->get_result();

  if (mysqli_num_rows($result) == 1)    
    $row = $result->fetch_assoc();
      $secid = $row["id"];
   else 
      header("LOCATION: index.php");
  

  $sql = "SELECT 
  maps.id,
  maps.name,
  maps.description,
  maps.date,
  maps.mcversion,
  maps.mapid,
  maps.category,
  maps.format,
  maps.userid,
  users.username,
  users.rank,
  users.verified,
  users.mc_username,
  (SELECT COUNT(*) FROM likes WHERE likes.mapid = maps.id) AS likes,
  (SELECT COUNT(*) FROM downloads WHERE downloads.mapid = maps.id) AS downloads,
  (SELECT COUNT(*) FROM subscribe WHERE subscribe.channelid = maps.userid) AS subscribes,
  (SELECT COUNT(*) FROM views WHERE views.mapid = maps.id) AS views
  FROM maps
  INNER JOIN users 
      ON maps.userid = users.id
  WHERE maps.id = '$secid'";

  $result = mysqli_query($con,$sql);

  if (mysqli_num_rows($result) > 0) 
      $row = mysqli_fetch_assoc($result);
   else 
      header("LOCATION: index.php");
  

 else 
    header("LOCATION: index.php");

【问题讨论】:

@David 说“这东西存在吗?”这看起来像是一种被误导的方式。最好将这些和JOIN 组合在一起。 这个概念本身对 SQL 注入是不安全的,因为您只是从表中获取值并将其直接放入您的 SQL 字符串中。如果表值本身不好(假设您检索了一个名称,例如“O'Connell”,然后按名称进行查找)。相反,您应该始终使用准备好的语句。您已经对maps 进行了查询,因此只需使用大查询字符串并将WHERE maps.id = '$ecid'" 替换为WHERE maps.id=? @SloanThrasher 仅在 50% 的情况下使用它。 @SloanThrasher “某种已经验证过的”正是人们在泄露后审计报告中提出的内容。这是弱验证,并且在修复微不足道时会引入不必要的风险。 由于第二个查询中使用的 $secid 来自于第一个查询解释了为什么它被称为“Second Order SQL 注入” 【参考方案1】:

一般经验法则:如果您的查询有变量插值,就像 $secid 一样,那么可能没有

使用带有占位符值的准备好的语句来确保您没有注入问题。其他任何事情都需要您手动调查和验证。 仔细彻底

由于$secid 来自数据库,因此您无法确定它是什么。这可能是一个VARCHAR 列,或者如果现在不是,它可能在将来。这就是使 SQL 注入成为永久威胁的原因。今天有充分根据的假设在以后可能会被证明是危险的。

在这种特殊情况下,没有理由不使用占位符值。第一个查询具有可疑的效用,确实如此。第二个可以而且应该使用完全相同的方法,出现 ? 而不是一个值。

作为强迫自己编写安全代码的一种方式,在定义查询时只使用单引号字符串。这样,任何意外的 SQL 注入都变得无害,您将获得显示在数据库中的文字 $ 值而不是用户数据,并且这些在测试中很容易发现。除非您去寻找它们,否则不会出现 SQL 注入错误。

【讨论】:

【参考方案2】:

这是一个更好的解决方案,对吧?

if(isset($_GET['id']) && $_GET['id'] != null) 
  $id = $_GET['id'];

  $stmt = $mysqli->prepare("SELECT 
  maps.id,
  maps.name,
  maps.description,
  maps.date,
  maps.mcversion,
  maps.mapid,
  maps.category,
  maps.format,
  maps.userid,
  users.username,
  users.rank,
  users.verified,
  users.mc_username,
  (SELECT COUNT(*) FROM likes WHERE likes.mapid = maps.id) AS likes,
  (SELECT COUNT(*) FROM downloads WHERE downloads.mapid = maps.id) AS downloads,
  (SELECT COUNT(*) FROM subscribe WHERE subscribe.channelid = maps.userid) AS subscribes,
  (SELECT COUNT(*) FROM views WHERE views.mapid = maps.id) AS views
  FROM maps
  INNER JOIN users 
  ON maps.userid = users.id
  WHERE maps.id = ?");

  $stmt->bind_param('i', $id);

  $stmt->execute();

  $result = $stmt->get_result();

  if (mysqli_num_rows($result) == 1)    
    $row = $result->fetch_assoc();
   else 
      header("LOCATION: index.php");
      die();
  

 else 
    header("LOCATION: index.php");
    die();

【讨论】:

是的!正确的解决方案 感谢您的回答! :)

以上是关于这个查询是不是受到 sql 注入的保护? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

这个参数化查询是不是对 SQL 注入开放?

这个 Python 代码是不是容易受到 SQL 注入的影响? (SQLite3)

这个 Rails 3 搜索是不是容易受到 SQL 注入的攻击?

Symfony/Doctrine 中的 SQL 注入

如何保护带有参数化表名的查询不被注入

在 SQL 注入中使用 LIKE 构建查询是不是安全?