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

时间:2012-07-13 14:45:45

标签: php postgresql optimization

考虑到一个项目将在多个开发人员中工作并且将不断更新和维护,考虑到可读性和安全性,下面两个代码中的哪些代码可以被认为是PHP中的最佳实践?如果我们谈论绩效,the second option will probably be a little better,但有办法解决这一点。

选项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

5 个答案:

答案 0 :(得分:7)

不要这样做。

我只能假设anti_injection是某种自定义过滤功能,这是一个坏主意™。如果确实希望采用其中任何一种想法,那么您应该使用mysql_real_escape_string

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

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

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

此外,您似乎以明文形式存储密码。 This is a bad idea.您应该研究一种强密码存储哈希算法,例如bcrypt,这使得从哈希中获取明文密码非常困难。

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

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

更新:你提到你正在使用postgres。您可以使用PDO从PHP运行参数化查询,如described briefly here

答案 1 :(得分:3)

这些选项都不是最佳做法,如果仅用于可疑的anti_injection,这几乎肯定不会像宣传的那样有效。还有以下问题:

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

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

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

答案 2 :(得分:2)

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

此外,如果我的用户名为"123456",我将无法登录,因为您将其转义为\"123456\",并且无法通过“length&lt; = 8”检查。

答案 3 :(得分:1)

如果您需要安全性和性能,我建议您使用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';
}

答案 4 :(得分:0)

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

作为最佳实践,不要改变超级全局($ _GET,$ _POST,$ _REQUEST,$ _SYSTEM等)我想不出一个违反此规则会提高性能的例子,任何修改都会导致不确定性和混乱。

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

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

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

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