我的PHP登录系统有多安全?
我是PHP新手,这也是我第一次登录系统,所以如果你们能查看我的代码,看看是否能发现任何安全漏洞,那就太好了: 注意:我正在清理所有用户输入,尽管这里没有显示 注册: 步骤1:我获取用户选择的密码,并通过此函数运行它:我的PHP登录系统有多安全?,php,security,authentication,encryption,login,Php,Security,Authentication,Encryption,Login,我是PHP新手,这也是我第一次登录系统,所以如果你们能查看我的代码,看看是否能发现任何安全漏洞,那就太好了: 注意:我正在清理所有用户输入,尽管这里没有显示 注册: 步骤1:我获取用户选择的密码,并通过此函数运行它: encrypt($user_chosen_password, $salt); function encrypt($plain_text, $salt) { if(!$salt) { $salt = uniqid(rand(0, 1000000));
encrypt($user_chosen_password, $salt);
function encrypt($plain_text, $salt) {
if(!$salt) {
$salt = uniqid(rand(0, 1000000));
}
return array(
'hash' => $salt.hash('sha512', $salt.$plain_text),
'salt' => $salt
);
}
步骤2:然后我将哈希和salt($password['hash']
和$password['salt']
)存储在数据库的用户表中:
id | username | password | salt | unrelated info...
-----------------------------------------------------------
1 | bobby | 809a28377 | 809a28377f | ...
fd131e5934
180dc24e15
bbe5f8be77
371623ce36
4d5b851e46
encrypt($user_entered_password, $salt);
user_id | key
------------------------------------------------------------
1 | 431b5f80879068b304db1880d8b1fa7805c63dde5d3dd05a5b
登录:
步骤1:我获取用户输入的用户名,并在数据库中查找是否返回了任何行。在我的网站上,没有两个用户可以共享相同的内容
用户名,因此用户名字段始终具有唯一值。如果我返回1行,我会为该用户抓取盐
第2步:然后我通过加密功能运行用户输入的密码(如上所述),但这次我还提供了从数据库检索到的salt:
id | username | password | salt | unrelated info...
-----------------------------------------------------------
1 | bobby | 809a28377 | 809a28377f | ...
fd131e5934
180dc24e15
bbe5f8be77
371623ce36
4d5b851e46
encrypt($user_entered_password, $salt);
user_id | key
------------------------------------------------------------
1 | 431b5f80879068b304db1880d8b1fa7805c63dde5d3dd05a5b
步骤3:我现在有了与此变量匹配的正确密码:$password['hash']
。因此,我对数据库进行了第二次查找,以查看
输入的用户名和散列密码一起返回一行。如果是,则用户的凭据是正确的
步骤4:为了在用户的凭据通过后登录,我生成一个随机唯一字符串并对其进行散列:
$random_string = uniqid(rand(0, 1000000));
$session_key = hash('sha512', $random_string);
然后,我将$session\u键插入数据库中的活动会话
表:
id | username | password | salt | unrelated info...
-----------------------------------------------------------
1 | bobby | 809a28377 | 809a28377f | ...
fd131e5934
180dc24e15
bbe5f8be77
371623ce36
4d5b851e46
encrypt($user_entered_password, $salt);
user_id | key
------------------------------------------------------------
1 | 431b5f80879068b304db1880d8b1fa7805c63dde5d3dd05a5b
第五步:
我将在最后一步中生成的未加密的唯一字符串($random\u string
)设置为cookie的值,我称之为活动\u会话
:
setcookie('active_session', $random_string, time()+3600*48, '/');
第6步:
在myheader.php
include的顶部有以下检查:
if(isset($_COOKIE['active_session']) && !isset($_SESSION['userinfo'])) {
get_userinfo();
}
get_userinfo()
函数查找数据库中的users
表,并返回一个关联数组,该数组存储在名为userinfo
的会话中:
$_SESSION['userinfo'] = array(
'user_id' => $row->user_id,
'username' => $row->username,
'dob' => $row->dob,
'country' => $row->country,
'city' => $row->city,
'zip' => $row->zip,
'email' => $row->email,
'avatar' => $row->avatar,
'account_status' => $row->account_status,
'timestamp' => $row->timestamp,
);
//首先,此函数获取活动会话cookie的值并对其进行哈希运算以获取会话密钥:
hash('sha512', $random_string);
//然后,它在活动会话
表上进行查找,查看此键
的记录是否存在,如果存在,它将获取与该记录关联的用户id
,并使用该id在用户
表上进行第二次查找,以获取用户信息
:
$_SESSION['userinfo'] = array(
'user_id' => $row->user_id,
'username' => $row->username,
'dob' => $row->dob,
'country' => $row->country,
'city' => $row->city,
'zip' => $row->zip,
'email' => $row->email,
'avatar' => $row->avatar,
'account_status' => $row->account_status,
'timestamp' => $row->timestamp,
);
如果userinfo
会话存在,我知道该用户已通过身份验证。如果它不存在,但活动会话
cookie存在,则检查
php
文件的顶部将创建该会话
我之所以使用cookie而不是单独使用会话,是为了持久化登录。因此,如果用户关闭浏览器,会话可能会消失,但
cookie仍然存在。由于在header.php
的顶部有一个检查,会话将被重新创建,用户可以作为一个登录用户使用
在用户中,一切正常
注销:
步骤1:未设置userinfo
会话和活动会话
cookie
步骤2:删除数据库中活动会话
表中的相关记录
注意:我能看到的唯一问题(可能还有很多其他问题)是,如果用户通过在浏览器中自己创建
活动会话
cookie来伪造该cookie。当然,他们必须设置一个字符串作为cookie的值,该字符串在加密后必须与活动会话
表中的记录匹配,我将从该表中检索用户id
,以创建该会话。我不确定实际情况下,用户(可能使用自动程序)正确猜测他们不知道的字符串,然后将对其进行加密,并与数据库中active\u sessions
表中的字符串进行匹配,以获取用于构建该会话的用户id
很抱歉,这篇文章太大了,但因为这是我网站的关键部分,而且由于我缺乏经验,我只想让更有经验的开发人员来运行它,以确保它实际上是安全的
那么,您是否发现这条路线存在任何安全漏洞,以及如何改进
…通过加密功能运行用户输入的密码
那么,密码是如何从浏览器传输到服务器的呢?您没有提到防止中间人攻击。您应该包括某种超时或故障切换,以防止暴力攻击。有很多方法可以做到这一点,包括基于IP的阻塞、增量超时等。这些方法都无法阻止黑客,但它们会让黑客变得更加困难 另一点(你没有提到,所以我不知道你的计划)是失败消息。使故障信息尽可能模糊。提供类似“该用户名存在,但密码不匹配”的错误消息可能会对最终用户有所帮助,但会破坏登录功能。您刚刚转换了一个蛮力攻击,该攻击需要
O(n^2)
时间才能O(n)
+O(n)
。黑客不需要尝试彩虹表中的每个排列(例如),而是首先尝试用户名的所有值(使用设置的密码),直到失败消息更改。然后,它知道一个有效的用户,只需强制输入密码
按照这些思路,您还应该确保用户名存在和不存在的时间相同。当用户名实际存在时,您正在运行其他进程。因此,用户名存在时的响应时间比用户名不存在时的响应时间要长。一个技术高超的黑客可以对页面请求进行计时,以找到一个有效的用户名
同样,您应该确保,除了过期的cookie之外,您