1

我正在尝试使用会话来存储登录尝试的数量。当达到最大登录尝试次数时,我将客户端的 IP 地址存储在黑名单表中。

我已经考虑到的一些事情,您可能需要了解:

  • 我在session_regenerate_id();设置会话值后使用。
  • 除了会话之外,我没有使用任何 cookie,因为这不是必需的,也不是 2012 年:p
  • 用户 ip 被列入黑名单,直到我从黑名单表中手动删除他的行。
  • 是一个已定义的SESSION_MAX_ATTEMPTS常数并设置为 5。
  • index.php?module=login&task=blacklist页面只是向用户显示它已被列入黑名单的消息。此页面没有任何功能。
  • 我正在使用自定义构建 php 框架,所以我不得不将一些称为方法的 OOP 转换为简化的 php 代码。

在执行登录查询之前调用以下函数:

private function preventAttack()
{
    $blocked = getData("SELECT count(*) as blocked FROM blacklist WHERE ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
    if($blocked[0]["blocked"] == "1")
    {
        redirect("index.php?module=login&task=blacklist");
    }
    $old = (int)$this->session->get("login_attempts");
    if(!empty($old))
    {           
        if($old > SESSION_MAX_ATTEMPTS)
        {
            setData("INSERT INTO blacklist SET ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
            redirect("index.php?module=login&task=blacklist");
        }
        else
        {
            $old++;
            $this->session->set("login_attempts",$old);
        }
    }
    else
    {
        $this->session->set("login_attempts", 0);
    }
}

第一个 if 语句有效,包括两个查询,但我被困在存储尝试次数的最佳方式是什么以及 ++ 它的最佳方式是什么?也许你们可以让我朝着正确的方向前进。

如果您对我的代码有任何疑问,请添加评论。我知道它有点不可读,因为它来自我的框架,我在发布之前已经翻译了一点。

4

2 回答 2

4

将失败尝试的次数存储在数据库中,而不是会话中。注意:您可能需要在其自己的记录中保留每个故障及其时间戳(并忽略/删除任何早于阈值的内容)。

顺便说一句,针对 deceze 的评论:

这种方法的巨大缺陷:会话依赖于客户端发送 cookie。真正的攻击者根本不会发回 cookie。ziiiing您必须通过 IP 进行所有操作。

对此的解决方案是,您不接受没有在其他地方设置的有效会话 cookie 的登录尝试。

于 2012-07-16T12:33:32.093 回答
0

非常感谢大家,我从你们的评论中学到了很多东西。对于有同样问题的用户,我将解释我学到了什么以及我如何使用这些知识。

到目前为止我学到了什么:

  1. 真正的攻击者根本不会发回 cookie。因此,在这种情况下,使用 cookie 或会话没有任何意义。
  2. 如果您想将攻击者列入黑名单,请使用自动为您执行此操作的防火墙。从您的脚本中执行此操作没有任何意义,会话太容易被规避,如果您检查 IP 地址,您可能会在同一外部 IP 上屏蔽整个办公室或学校。
  3. 无论您做什么:仅将登录尝试数据存储在服务器上的数据库/平面文件/等中。用户或攻击者将无法如此轻松地编辑此数据。
  4. 如果您确实将数据存储在 Web 服务器上以提高性能,请将其存储在文件中,而不是数据库中。

如果我忘记了什么,请发表评论,我会编辑这篇文章。

我咨询了我的托管服务提供商,他们已经使用上述防火墙等解决方案阻止了许多攻击者。所以我将停止尝试在我的脚本中也这样做。

我的脚本现在已修复,仅将猜测密码的用户和新手黑客列入黑名单:

private function preventAttack()
{
    $blocked = getData("SELECT count(*) as blocked FROM blacklist WHERE ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
    if($blocked[0]["blocked"] == "1")
    {
        redirect("index.php?module=login&task=blacklist");
    }
    $old = (int)$this->session->get("login_attempts");
    if($old > 0)
    {           
        if(($old + 1) >= SESSION_MAX_ATTEMPTS)
        {
            setData("INSERT INTO blacklist SET ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
            $this->session->set("login_attempts", 0);
            redirect("index.php?module=login&task=blacklist");
        }
        else
        {
            $old++;
            $this->session->set("login_attempts",$old);
        }
    }
    else
    {
        $this->session->set("login_attempts", 1);
    }
}

由于我不太确定该平台将获得多少用户,并且我不希望 mysql 服务器负载可能很高,所以我决定不在数据库中存储登录尝试。也许在未来,谁知道呢。

于 2012-07-16T12:45:17.187 回答