代码之家  ›  专栏  ›  技术社区  ›  Brian Bauman

这个PHP身份验证函数是如何被破解的?

  •  1
  • Brian Bauman  · 技术社区  · 15 年前

    这是我编写的一个递归函数,用于确定给定用户是否有权查看页面上的内容。基本上按以下方式称之为:

    if(authorize($_SESSION['user']['user_id'], $necessaryClearance)){
        //Output restricted content
    } else{
        //Inform user they are not authorized
    }
    

    //This function checks if the user is authorized to view the page
    //It returns 1 if access is granted and a 0 if access is denied
    function authorize($id, $clearance){
     //$clearance == array
        if (is_array($clearance)){
       //if yes Iterate array through Authorize($id, $clearance[])
      foreach($clearance as $userStatus){
       $tally += authorize ($id, $userStatus);
    
      }
       return $tally;
     //if no check if $clearenance is equal to a string
     }else if (is_string ($clearance)){
      $string = "SELECT status
    
      FROM users
          WHERE id = '$id'
          LIMIT 1";
      //If result returned.
      if($userData = mysql_fetch_array(Query($string))){
       if($clearance == $userData['status']){
        return 1;
       }else{ 
        return 0;
       }
      } else{
       return 0;
      }
      // if no check if $clearance is equal to a number  
     }else if(is_numeric($clearance)){
      $string = "SELECT level
          FROM users
          WHERE id = '$id'
          LIMIT 1";
      //If result returned
      if($userData = mysql_fetch_array(Query($string))){ 
       // if number is less than or equal to clearance level allow access
       if($userData['level'] <= $clearance){
        return 1;
       }else{ 
        return 0;
       }
      } else{
       return 0;
      }
    
     }else{
      //if nothing matches the page dies
      die('Authorization has failed.');
     }
    }
    

    代码中是否存在明显的安全漏洞?

    5 回复  |  直到 11 年前
        1
  •  2
  •   Bill Karwin    15 年前

    SQL注入是一个严重的风险,你应该尽你所能来防范它。即使您认为您的$user_id来自会话数据,您仍然必须考虑会话数据的来源。你说是数据库,但它是怎么进入数据库的?

    只需进行防御性编码。在这种情况下,这是非常简单和容易的——只要将$user_id强制为一个整数,就可以确保在将其插入查询时不会出现额外的SQL语法。

    另外,你的函数不需要使用递归。下面是一个以更简单的方式执行相同功能的示例:

    function authorize($user_id, $clearance) {
      // coerce to integer to defend against SQL Injection
      $user_id = (int) $user_id;
    
      $sql = "SELECT status FROM users WHERE id = {$user_id}";
      $userData = mysql_fetch_array(Query($sql));
    
      $tally = 0;
      foreach ((array) $clearance as $userStatus) {
        if (is_numeric($userStatus)) {
          $tally += ($userData["level"] <= $userStatus);
        } else {
          $tally += ($userData["status"] == $userStatus);
        }
      }
    
      return $tally;
    }
    

    这个简单的代码唯一不支持的是$clearance中的嵌套数组。但你真的需要支持吗?

    附言:我也建议你换成 PDO . 它易于使用,并且支持带参数的SQL查询,这对SQL注入是更好的防御。例如:

        $sql = "SELECT status FROM users WHERE id = ?";
        $stmt = $pdo->prepare($sql);
        $result = $stmt->execute(array($user_id));
        $userData = $stmt->fetch();
    
        2
  •  6
  •   Jacob Relkin    15 年前

    $id 参数!

    SQL Injection 攻击。

        3
  •  0
  •   rook    15 年前

    $id 从哪里来?它是get/post/cookie值吗?因为如果是的话你可以说 $id=1

    还有一种情况是SQL注入。你可以注入一个简单的重言式,比如 ' or 1=1 或者做一些更阴险的事,比如 ' and 0=1 union select "<?php eval($_GET[e])?>" into outfile /var/www/backdoor.php .

        4
  •  0
  •   ITroubs    15 年前

        5
  •  0
  •   John Pancoast    15 年前

    即使你现在百分之百地知道$id从哪里来,也不一定会认为总是这样。如果你的应用程序增长了怎么办?如果你有更多的人在做呢?如果在$会话值之外使用不同的值调用此函数,会怎么样?当然,你可能知道你的应用程序的来龙去脉,你知道这可能永远不会发生,但这仍然是一个坏的做法。至少,您可以使用mysql_real_escape_字符串。