繁体   English   中英

PHP中使用$ _POST和$ _GET变量的最佳实践

[英]Best practices in PHP using $_POST and $_GET variables

考虑到一个项目将工作多个开发人员并且将不断更新和维护,考虑到可读性和安全性,下面两个代码中的哪些代码可以被认为是PHP中的最佳实践? 如果我们谈论性能, 第二种选择可能会好一点 ,但有办法解决这一点。

选项1

$user = $_POST['user'];
$pass = $_POST['pass'];

// Prevent SQL Injection and XSS
$user = anti_injection($user);
$pass = anti_injection($pass);

if(strlen($user) <= 8 && strlen($pass) <= 12)
{
    // SQL query
    $sql = "SELECT id 
            FROM users 
            WHERE username = '$user' AND password = '$pass';";
}

选项2

// Retrieve POST variables and prevent SQL Injection and XSS
$_POST['user'] = anti_injection($_POST['user']);
$_POST['pass'] = anti_injection($_POST['pass']);

if(strlen($_POST['user']) <= 8 && strlen($_POST['pass']) <= 12)
{
    // SQL query
    $sql = "SELECT id 
            FROM users 
            WHERE username = '" . $_POST['user']. "' AND password = '" . $_POST['pass'] . "';";
}

编辑1

我没有使用MySQL,我的数据库是PostgreSQL

不要做任何一件事。

我只能假设anti_injection是某种自定义过滤功能,这是一个坏主意™。 如果你真的想采用这些想法,你应该使用mysql_real_escape_string

编写SQL查询时保持安全的唯一方法是使用参数,例如通过MySQLi。 mysql_*函数无论如何都会被弃用,所以你最好尽快移动。

实际上, mysql_real_escape_string并不是针对注入攻击的万无一失的防御措施。 考虑查询中的整数比较,例如WHERE $var > 30 我可以成功地将1=1 or 100注入$var ,并完全打破逻辑。

参数将数据与查询语言完全分开,完全降低了注入风险。 服务器接收包含参数表示法的查询和要插入的一组值,因此它可以完全不同地处理查询语言和数据。

此外,您似乎以明文形式存储密码。 这是 个坏 主意。 您应该研究一种强密码存储哈希算法,例如bcrypt,这使得从哈希中获取明文密码变得非常困难。

MD5和SHA1不是密码存储的理想选择,因为它们设计得很快,这意味着攻击者可以快速破解强大的密码。 现代GPU每秒可实现50亿MD5哈希值。 事实上,有些人使用专用的哈希破解装置,其中一些可以破解MD5, 每秒450亿次哈希

您还应该看看这些令人敬畏的问题,这些问题完全涵盖SQL注入攻击,密码存储以及许多其他安全问题:

更新:你提到你正在使用postgres。 您可以使用PDO从PHP运行参数化查询,如此处简要描述

这些选项都不是最佳实践 ,只是因为可疑的anti_injection几乎肯定不像宣传的那样有效。 还有以下问题:

  • 在验证输入数据之前将其重新排列
  • 存储明文密码
  • 手动构建SQL查询而不是使用绑定参数

根据项目的范围,最后一个可能是可以接受的。

关于性能,第一个选项在理论上会更快,因为它的阵列索引更少。 但差别肯定会很小,根本不可观察到。 第一个选项也更具可读性,并提供更好的抽象,所有这些只是可以忽略不计的额外内存量。

两者都错了。 您似乎将密码存储为纯文本,这只是一个问题。

此外,如果我的用户名是"123456" ,我将无法登录,因为你将它转义为\\"123456\\" ,这将失败“长度<= 8”检查。

如果你想要安全性和性能,我建议使用PDO。 使用参数时不能sql注入。 下面是一个例子,你需要“定义”以下的mysql参数才能工作。

这也允许数据库缓存您的查询,因为每次使用不同的参数执行时它都不会更改,这也会提高性能。

:p_user and :p_pass

用于表示参数和

array ( ':p_user' => $user, ':p_pass' => $pass ' )

将参数设置为您需要传入的值。

您还应该考虑添加密码盐,并将其存储在数据库中,以便在您的数据库遭到破坏时,您的密码不会清楚地显示给黑客。

class users{ 
  function __construct() {
    define('MySQLHost', 'localhost');
    define('MySQLName', 'databasename');
    define('MySQLUser', 'username');
    define('MySQLPass', 'password');
    define('pwsalt', 'tScgpBOoRL7A48TzpBGUgpKINc69B4Ylpvc5Xc6k'); //random characters
  }

  static function GetQuery($query, $params)
  {
    $db = new PDO('pgsql:host='.MySQLHost.';dbname='.MySQLName.';', MySQLUser, MySQLPass);
    $cmd = $db->prepare($query);
    $cmd->execute($params);

    if($cmd->rowCount()==0)
      return null;
    return $cmd->fetchAll();
  }

  static function GetUser($user, $pass)
  {
    $query = "select id
      from `users`
      where username = :p_user and password = :p_pass";

    $rows = users::GetQuery($query, array(
      ':p_user' => $user,
      ':p_pass' => sha1($pass.pwsalt) //Append the salt to the password, hash it
    ));

    return $rows;
  }
}

$user = $_POST['user'];
$pass = $_POST['pass'];
if( strlen($user) <= 8 && strlen($pass) <= 12 )
{
  $result = users::GetUser($user, $pass);
  if($result != null)
    print 'Login Found';
}

虽然我同意其他海报,但不要试图“重新发明”关于SQL安全的问题,问题似乎是关于性能以及如何使用超级全局。

作为最佳实践,不要改变superglobals($ _GET,$ _POST,$ _REQUEST,$ _SYSTEM等)我想不出一个违反此规则会改善你的表现的例子,任何修改都会导致不确定性混乱在路上。

所以在这种情况下,两种选择都不正确。 Option1不必要地复制变量(根据Google性能文档,禁止使用)。 选项2改变超全球,这违反了上述格言。 而是做类似的事情:

$user = anti_injection( $_POST['user'] );
$pass = anti_injection( $_POST['pass'] );

if( strlen($user) <= 8 && strlen($pass) <= 12 ) ...

不过,我应该重申,“自制卫生”是一个令人恐惧的前景,其他评论者在这一点上已经详尽阐述。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM