[英]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注入攻击,密码存储以及许多其他安全问题:
这些选项都不是最佳实践 ,只是因为可疑的anti_injection
几乎肯定不像宣传的那样有效。 还有以下问题:
根据项目的范围,最后一个可能是可以接受的。
关于性能,第一个选项在理论上会更快,因为它的阵列索引更少。 但差别肯定会很小,根本不可观察到。 第一个选项也更具可读性,并提供更好的抽象,所有这些只是可以忽略不计的额外内存量。
两者都错了。 您似乎将密码存储为纯文本,这只是一个问题。
此外,如果我的用户名是"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.