如何防止PHP网站中的多次登录

Adi*_*ing 18 php security

我想防止php应用程序中的多次登录.

首先,我在用户表中创建登录状态(活动,非活动).

当用户A登录时,用户状态将设置为"活动",如果用户注销,状态将设置为"非活动".当另一个客户端尝试使用相同的用户帐户登录时,我检查用户表.如果用户仍处于活动状态,则会将错误登录信息发送给用户.

出现问题,如果用户关闭浏览器,则可以更新用户表中的状态,因为用户未单击注销.

你有什么建议吗?

Lac*_*cD. 18

(请注意,尽管此处的技术仍然有些有效;但不应逐字复制PHP示例,因为有更安全的方法可以在SQL查询中合并用户提供的值)


不是存储用户是否处于活动状态\非活动状态,而是最好存储一些可以基于每个动作对用户进行检查的属性; 就像在每次用户尝试执行需要身份验证的操作时一样,它会在进行之前检查此属性是否匹配.

我建议你做以下事情;

首先,创建一个散列唯一标识,每当他们登录的用户.我会想象一个sha1time()就足以避免冲突.无论您选择什么,请确保它的变化足以使另一个登录用户接收相同哈希的机会极低(例如,不要散列IP地址或浏览器的用户代理,因为这些不是变化的足够).

其次,在登录时将此哈希存储在数据库和用户会话中.这样做会有效地"注销"前一个用户,因为每次有人登录时哈希都应该不同.

由于我们正在使用会话,因此cookie应自动放置在用户的浏览器中,该浏览器将包含一个唯一ID,用于标识用户对其会话数据的唯一ID.cookie的内容并不是真正令人担忧的.

接下来,创建一个名为authenticateUser()或类似的函数,该函数将在每个脚本的开头调用,以确保用户通过身份验证.此脚本应查询数据库,检查具有用户ID的用户是否具有与用户哈希匹配的哈希.

例如:

function authenticateUser($id, $hash, $databaseLink) {
    # SQL
    $sql = 'SELECT EXISTS(
               SELECT 1
               FROM `tbl_users`
               WHERE `id` = \''.mysql_real_escape_string($id).'\'
               AND `hash` = \''.mysql_real_escape_string($hash).'\'
               LIMIT 1
           );';

    # Run Query
    if ($query = mysql_query($sql, $databaseLink)) {
        # Get the first row of the results
        # Assuming 'id' is your primary key, there
        # should only ever be one row anyway.       
        $result = mysql_fetch_row($query);

        # Casting to boolean isn't strictly necessary here
        # its included to indicate the mysql result should
        # only ever been 1 or 0.
        return (bool)($result[0]);
    } else {
        # Query error :(
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我们简单地传递authenticateUser()用户的ID,hash(根据您的会话数据)和database link(对于一个数据库连接,你将不得不早点打开).

如果authenticateUser()返回true,则对用户进行身份验证.如果false用户不是OR,则数据库不可用或存在SQL错误.

但请注意,这将增加您的服务器负载,因为每页请求发送一次数据库请求.在数千人在任何特定时间登录的巨型项目中执行此操作可能不是那么明智.我相信有人可以提出改进建议.

此外,等待cookie过期并不是强制非活动人员注销的最佳方式,因为您永远不应该信任cookie.相反,您可以添加一个名称last_active,您可以在每次验证用户时更新该列.这也会增加服务器负载,但允许您通过删除hash那些非活动3小时的用户来手动覆盖过时登录.

  • 当用户直接关闭浏览器和会话销毁时会发生什么? (2认同)

pro*_*mer 9

这里有一个解决方案并不需要不断的数据库访问工作...

(这样可以避免每次请求/刷新页面时都要根据数据库值检查session_id(),从而减轻数据库/服务器压力)...

1.登录时,为此用户获取存储在数据库中的预先存在的session_id,并执行以下操作:

session_id("the pre-existing session id in the database goes here");
session_start();
session_destroy();
Run Code Online (Sandbox Code Playgroud)

2.然后启动一个新会话并将此新session_id保存到数据库,覆盖前一个会话.如果有一个活动的话,这将注销该用户的上一个会话(使用此帐户有效地注销其他人).

尝试一下,让我知道如果这样做的话!


Rob*_*bri 5

您应该做的是检查他们在尝试登录时是否在最后几分钟内处于活动状态.这可以使用lastonline标记来完成,并且应该在用户表中的每个页面请求上设置.

如果没有使用javascript,您可以在登录时检查用户是否在过去15分钟内处于活动状态.如果没有,您可以以新用户身份登录.

你也可以用javascript来做.每分钟左右发一次ajax电话.

<script>
setInterval(function() {
  // do the ajax call
}, 60000);
</script>
Run Code Online (Sandbox Code Playgroud)

让这个调用转到一个脚本,该脚本将编辑用户db中的lastonline标记.当您尝试登录时,检查用户数据库是否上一个在线邮票超过了分钟,并检查您是否可以登录.当您在页面上但在最后15分钟内您没有活动并且您不希望其他人登录时,这将有所帮助.


Pau*_*xon 5

您可以更改模型,以便只能登录最新用户.

如果您记录每个用户看到的最新会话ID,当他们第二次登录时,您可以删除任何当前存在的会话,从而有效地将其记录下来.

对于普通用户来说,事情似乎"正常".如果您想阻止"异常"用户分发他们的登录凭据,这应该起到抑制作用.

  • 好吧,我所说的是当user_B登录时,user_A会自动注销.您可能有充分的理由想要阻止user_B的登录,但您还没有说清楚为什么这样做更可取.我的建议解决了等待会话超时允许重新登录的问题,同时仍然阻止用户登录两次. (2认同)