PHP登录安全思想
我想到了一个系统来登录用户并验证他们在页面上的登录。PHP登录安全思想,php,security,login,Php,Security,Login,我想到了一个系统来登录用户并验证他们在页面上的登录。 我意识到有很多系统,但我主要是好奇我的想法是否好。我做了一些挖掘,但大多数结果似乎遗漏了我一直认为重要的实践(如密码加密等)。我可能会更努力地寻找一个预先制定的解决方案,因为它可能更安全,但我还没有真正研究过应用程序安全性,希望得到一些反馈 当用户登录时,他们的姓名和密码将根据数据库进行验证,密码将使用SHA256和随机生成的salt进行加密,整个字符串(salt和加密密码均为128个字符长)。 以下是密码验证代码: function Va
我意识到有很多系统,但我主要是好奇我的想法是否好。我做了一些挖掘,但大多数结果似乎遗漏了我一直认为重要的实践(如密码加密等)。我可能会更努力地寻找一个预先制定的解决方案,因为它可能更安全,但我还没有真正研究过应用程序安全性,希望得到一些反馈 当用户登录时,他们的姓名和密码将根据数据库进行验证,密码将使用SHA256和随机生成的salt进行加密,整个字符串(salt和加密密码均为128个字符长)。 以下是密码验证代码:
function ValidatePassword($password, $correctHash)
{
$salt = substr($correctHash, 0, 64); //get the salt from the front of the hash
$validHash = substr($correctHash, 64, 64); //the SHA256
$testHash = hash("sha256", $salt . $password); //hash the password being tested
//if the hashes are exactly the same, the password is valid
return $testHash === $validHash;
}
如果登录有效,将为他们分配一个令牌。此令牌类似于密码加密,但存储加密的历元以及另一个随机salt。令牌、登录时间、过期时间和用户名存储在数据库中,用户名和令牌作为会话信息传输
以下是创建令牌的代码:
function loginUser($email)
{
$thetime = time();
$ip = $_SERVER['REMOTE_ADDR'];
$dbuser="///";
$dbpass="///";
$dbtable="tokens";
mysql_connect(localhost,$dbuser,$dbpass);
mysql_select_db("///") or die( "Unable to select database");
//Generate a salt
$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
//Hash the salt and the current time to get a random token
$hash = hash("sha256", $salt . $password);
//Prepend the salt to the hash
$final = $salt . $hash;
$exptime = $thetime + 3600;
//Store this value into the db
$query = "INSERT INTO `spanel`.`tokens` VALUES ('$final', $thetime, $exptime, $thetime, '$ip', MD5('$email') )";
mysql_query($query) or die ("Could not create token.");
//Store the data into session vars
$_SESSION['spanel_email'] = $email;
$_SESSION['spanel_token'] = $final;
return true;
}
当他们到达一个页面时,他们所拥有的令牌和用户名将根据DB进行检查。如果检查正常,则更新过期时间并加载页面。
这是代码:
function validateUser($page)
{
//Grab some vars
$thetime = time();
$ip = $_SERVER['REMOTE_ADDR'];
$token = $_SESSION['spanel_token'];
$email = $_SESSION['spanel_email'];
$dbuser="///";
$dbpass="///";
$dbtable="tokens";
mysql_connect(localhost,$dbuser,$dbpass);
mysql_select_db("///") or die( "Unable to select database");
//Global var
//Get the var for token expire
$token_expire = 3600;
//Validate the token
$query = "SELECT * FROM `tokens` WHERE `token` LIKE '$token' AND `user_id` LIKE MD5('$email') AND `exp` > $thetime";
$result = mysql_query($query) or die(mysql_error());
//Check if we have a valid result
if ( mysql_num_rows($result) != 1 ) {
//Logout the user
//Destroy the session
session_destroy();
//Redirect
header("location: /spanel/login.php?denied=1");
exit();
//(Since the token is already invalid, there's no reason to reset it as invalid)
}
$row = mysql_fetch_assoc($result);
//Update the token with our lastseen
$newexp = $thetime + $token_expire;
$query = "UPDATE `spanel`.`tokens` SET `exp` = $newexp, `lastseen_ip` = $thetime, `lastseen_ip` = '$ip' WHERE `token` LIKE '$token'";
mysql_query($query);
}
欢迎反馈(好的和坏的)。就像我说的,我没有做太多的安全工作,我希望得到一些提示
编辑:我担心我高估了我有效创建登录系统的能力。说这句话,我理解如果你决定停止试图找出这个可能有缺陷的想法的混乱
不过,下面是登录页面中的php代码。(在这里说了这么多之后,我意识到发布密码是一个很大的禁忌)
感谢您的反馈,我很高兴我缺乏知识的问题是在这里发现的,而不是在攻击后发现的。首先,这样的散列是不安全的。sha256很容易被破解,至少对于短密码是如此。你必须使用一些。看看是否可以找到一些实现,或者使用维基百科对sha256的“for循环”的建议。
此外,我没有得到您通过使用更多会话变量所实现的效果。我不明白validateuser()的作用是什么,它仍然依赖于会话id,或者我遗漏了什么。仅对salt/hash系统进行评论:将salt与密码一起存储在数据库中有点违背了salt的目的——如果您的数据库被破坏,salt从安全角度看将变得无用,因为它就在那里帮助猜测/破坏安全。salt的目的是通过向正在散列的值添加一个适当长度的秘密字符串来增加猜测散列单词所需的时间。类似于,我也看不出添加spanel_标记的原因。它似乎有效地做的只是确保会话在令牌过期后不再有效。由于
其中
条件的token和user_id的值都存储在会话中,并且仅在登录期间设置,因此它们不会更改
但除此之外,更重要的是:您的代码容易受到SQL注入的攻击。有了你在这里发布的知识,这将很容易。您只需执行以下步骤:
- 在电子邮件中查找具有
注入的用户列数: 如果输入了错误的列数,脚本将抛出MySQL错误,否则将显示“登录失败”。谢谢你UNION SELECT
- 通过使用以下查询:
值SELECT t1.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email);
被注入到每个记录中,而不是原始哈希列值。前导的00000000000000000000000000000000000000000000000000000000000 60E05BD1B195AF2F94112FA7197A5C88289058840CE7C6DF9693756BC250F55
s是salt,剩余的字符串是空密码字符串的salt SHA-256哈希值,这将生成有效密码 因此,我们在密码字段中输入一个空字符串,在电子邮件字段中输入以下内容:0
这应该足以作为任何用户获得“身份验证”。我希望这不是吹毛求疵,但我只是想确保您理解:哈希和加密是两件不同的事情——哈希算法的设计是不可逆的。看起来您试图做的是散列密码,而不是加密密码,这很好。如果您打算对密码进行加密,我认为这是一种不好的做法,因为您的系统永远不需要知道用户的实际密码。
loginUser
中的$password
来自哪里?您如何使用这些函数?谢谢,我将是散列,而不是加密。$password是一个我没有发现的错误(我回收了代码,没有更新那个变量)。我打算是$TheTime哇,你不了解SQL注入,但你想编写自己的身份验证协议…不完全是这样,salt提供了防止重播攻击(来自网络嗅探器)的保护。我同意每次都应该生成salt(或质询密钥),但如果数据库受到破坏,密码表也会受到破坏。这是一个好观点,我肯定误解了salt的一个关键方面。我们同意盐不应该以常青的方式储存在数据库中。@sivann你错了。这似乎不像HTTP摘要那样是一种质询-响应身份验证方案,客户端只发送摘要而不是密码。@sivann它仍然无法与CRAM相比:在CRAM中,(您不会调用它)将发送到客户端以将其合并到响应计算中,并使用响应而不是普通密码对用户进行身份验证。这就是您需要一个nonce的地方,以便响应只对这个仅对f有效的特定nonce有效
function HashPassword($password)
{
$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //get 256 random bits in hex
$hash = hash("sha256", $salt . $password); //prepend the salt, then hash
//store the salt and hash in the same string, so only 1 DB column is needed
$final = $salt . $hash;
return $final;
}
' UNION SELECT null, …, null WHERE ''='
SELECT t1.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email);
' UNION SELECT t2.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email) WHERE ''='