如何限制登录尝试-PHP&;MySQL&;共点火器

如何限制登录尝试-PHP&;MySQL&;共点火器,php,mysql,security,login,throttling,Php,Mysql,Security,Login,Throttling,我希望能够根据失败的尝试来限制登录尝试,但我有一些问题 我应该使用MySQL吗?(读到它可能会使DB紧张) 我应该按用户和系统范围节流,还是只在系统范围节流?(以防止普通人猜测密码) 我应该如何计算我的阈值?(因此它会自动适应变化/增长) 我应该如何检索此阈值?每次失败时查询/计算或存储在缓存中? 我应该用什么来调节油门?(读取一个响应,sleep()可能会导致服务器紧张) 有人有一些示例代码吗 我对这方面还不太熟悉,所以非常感谢你的帮助! 谢谢MySQL数据库能够每秒处理请求的音调,因此如果没

我希望能够根据失败的尝试来限制登录尝试,但我有一些问题

我应该使用MySQL吗?(读到它可能会使DB紧张)
我应该按用户和系统范围节流,还是只在系统范围节流?(以防止普通人猜测密码)
我应该如何计算我的阈值?(因此它会自动适应变化/增长)
我应该如何检索此阈值?每次失败时查询/计算或存储在缓存中?
我应该用什么来调节油门?(读取一个响应,sleep()可能会导致服务器紧张)

有人有一些示例代码吗

我对这方面还不太熟悉,所以非常感谢你的帮助!
谢谢

MySQL数据库能够每秒处理请求的音调,因此如果没有数千个用户,就不必担心瓶颈问题

你也可以使用sleep() 注意:PHP处理的用户比ASP.NET多——同样如此。如果你没有成千上万的用户,你可以使用睡眠方法,而不需要瓶颈

我通常的做法是存储登录尝试(IP、用户ID和时间戳)。 将其存储在表格中,并在您需要时重置表格(在一天中的特定时间或大小)。 如果用户ID+IP在“一定时间内”有超过“登录尝试次数”,请将用户重定向到一个页面,该页面告诉用户他/她已经尝试过多次,并且在接下来的15分钟内(或您喜欢的任何时间)将无法登录。 有点像我猜的“Windows”,但它很有魅力:)

我在单独使用APC时实现了一个,我就是这样使用它的:

// allow 60 requests every 30 seconds
// each request counts as 1 (expensive operations can use higher values)
// keep track of IPs by REMOTE_ADDR (ignore others)

$throttle = ph()->Throttle($ttl = 30, $exit = 60, $count = 1, $proxy = false);

if ($throttle === true)
{
    // IP exceded 30 requests in the last 60 seconds, die() here
}

else
{
    // $throttle is a float
    // number of requests in the last 30 seconds / 30 seconds

    /*
     1 req / 30 = 0,033 sec
     5 req / 30 = 0,166 sec
    10 req / 30 = 0,333 sec
    15 req / 30 = 0,5   sec
    20 req / 30 = 0,666 sec
    25 req / 30 = 0,833 sec
    30 req / 30 = 1     sec
    */

    usleep(intval(floatval($throttle) * 1000000));
}
我在我的前端控制器上使用它,并将值传递给我的路由方法,但这是另一回事

底线是,如果您使用APC,您能够在内存中保持非常快的速度,并且几乎没有内存消耗,因为APC遵循FILO方法。如果你需要更高的超时时间,你可以考虑使用一些不是基于内存的东西。 顺便说一句:MySQL支持带有内存引擎的表


睡眠问题():

典型的ApacheWeb服务器将PHP作为一个模块安装,每个实例将消耗大约10MB的RAM,为了避免超过可用RAM,您可以配置一些Apache设置来限制Apache能够启动的最大实例数

问题是,当您
sleep()
时,该实例仍处于活动状态,并且有足够的请求可能会占用所有可用插槽来启动新服务器,从而导致在某些挂起的请求完成之前无法访问您的网站

PHP AFAIK无法克服这一点,因此最终取决于您


系统范围节流的原理相同:

function systemWide($ttl = 86400, $exit = 360)
{
    if (extension_loaded('apc') === true)
    {
        $key = array(__FUNCTION__);

        if (apc_exists(__FUNCTION__) !== true)
        {
            apc_store(__FUNCTION__, 0, $ttl);
        }

        $result = apc_inc(__FUNCTION__, 1);

        if ($result < $exit)
        {
            return ($result / $ttl);
        }

        return true;
    }

    return false;
}
全系统功能($ttl=86400,$exit=360)
{
if(扩展插件加载('apc')==true)
{
$key=数组(_函数__);
如果(apc_存在(_函数)!=true)
{
apc_存储(_函数,0,$ttl);
}
$result=apc_inc(_函数,1);
如果($result<$exit)
{
返回($result/$ttl);
}
返回true;
}
返回false;
}

在如下表中记录失败的登录尝试:

FailedLogins
id
timestamp
ip
每次用户尝试登录时,您都会检查该用户的IP地址在过去Y秒内是否有X次失败的登录尝试


如果用户在Y秒内失败X次,您将显示一条错误消息或验证码。

据我所知,这是针对每个用户的节流是吗?如果是这样的话,您建议我如何实现一个系统范围的节流阀来防止分布式攻击?问题是,即使您没有用1秒的睡眠消耗CPU时间,您仍然会占用PHP进程那么长的时间。大多数前端服务器会迅速退化,导致整个服务器停机(类似于slashdot效应,但只有一个用户而不是一吨用户)。@ircmaxell:我知道,但您也只需要
sleep()
。@RS7:这是每IP限制。我不太清楚你所说的系统范围的节流是什么意思,但如果我得到你所说的,一个单键加上
apc_inc()
就可以完成整个系统的工作。@ircmaxell:你能给我一些建议吗?Thanks@user622470:MySQL的问题是,他不需要有数千个用户,只有一个知道如何快速建立数千个连接的用户。攻击者没有访问MySQL的权限,只有访问网页的权限。为什么要使用
id
列?