Security 什么是最好的分布式暴力对抗?
首先,有一点背景:我正在为CodeIgniter实现一个auth+auth系统,这已经不是什么秘密了,到目前为止,我正在获胜(可以这么说)。但我遇到了一个非常重要的挑战(大多数auth库都没有遇到,但我坚持正确处理):如何智能地处理大规模、分布式、可变用户名的暴力攻击 我知道所有的惯用伎俩:Security 什么是最好的分布式暴力对抗?,security,authentication,brute-force,Security,Authentication,Brute Force,首先,有一点背景:我正在为CodeIgniter实现一个auth+auth系统,这已经不是什么秘密了,到目前为止,我正在获胜(可以这么说)。但我遇到了一个非常重要的挑战(大多数auth库都没有遇到,但我坚持正确处理):如何智能地处理大规模、分布式、可变用户名的暴力攻击 我知道所有的惯用伎俩: 限制每个IP/主机的失败尝试次数#并拒绝违规者访问(例如Fail2Ban)-这不再有效 将上述内容与已知“坏”IP/主机的黑名单(如DenyHosts)结合起来,该黑名单依赖于落入#1的僵尸网络 IP/主机
- 它必须是安全的(+)以防DoS和暴力攻击,并且不引入任何新的漏洞,这些漏洞可能允许稍微狡猾的机器人继续在雷达下运行
- 它必须是自动化的。如果它需要人工操作员来验证每个登录或监视可疑活动,那么它在现实场景中是行不通的
- 它必须适用于主流网络使用(即高流失率、高容量和可由非程序员执行的开放注册)
- 它不能妨碍用户体验,以至于临时用户会感到恼火或沮丧(并可能放弃网站)
- 它不能涉及小猫,除非它们是真正安全的小猫
那么,让我们听听吧!你会怎么做?你知道我没有提到的最佳实践吗(哦,请说你知道)?我承认我确实有自己的想法(结合了第三和第四章的想法),但在让自己难堪之前,我会让真正的专家说出来;-) 看起来你是在试图防御。你对此无能为力。我们使用的是PKI,没有密码登录。这是有帮助的,但是如果你的客户偶尔有机会使用工作站,这就不太适用了
如果我正确理解暴力攻击的方式,那么就会不断尝试一个或多个用户名 这里有两个我认为还没有看到的建议:
- 我一直认为标准做法是在每个用户每次错误登录后都有一个短暂的延迟(一秒钟左右)。这阻止了暴力,但我不知道一秒钟的延迟能阻止字典攻击多久。(10000字字典==10000秒==大约3小时。嗯,不够好。)
- 与其在站点范围内减速,不如使用用户名节流阀。每一次错误的尝试都会使油门变得越来越猛(我想这会达到一个极限,这样真正的用户仍然可以登录)
- 检测猜测多个帐户的IP-408请求超时
- 检测猜测同一帐户的IP-408在大量(比如100次)猜测后请求超时
- 如果您可以控制密码设置,则显示给用户会鼓励他们选择更好的密码
- 如果您控制了登录页面,在进行少量(比如10次)的猜测之后
CREATE TABLE failed_logins( id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(16) NOT NULL, ip_address INT(11) UNSIGNED NOT NULL, attempted DATETIME NOT NULL ) engine=InnoDB charset=UTF8;
10 failed attempts = 1 second 20 failed attempts = 2 seconds 30 failed attempts = reCaptcha
SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);
// array of throttling $throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha'); // assume query result of $sql is stored in $row $sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins'; $latest_attempt = (int) date('U', strtotime($row['attempted'])); // get the number of failed attempts $sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)'; // assume the number of failed attempts was stored in $failed_attempts krsort($throttle); foreach ($throttle as $attempts => $delay) { if ($failed_attempts > $attempts) { // we need to throttle based on delay if (is_numeric($delay)) { $remaining_delay = time() - $latest_attempt - $delay; // output remaining delay echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt'; } else { // code to display recaptcha on login form goes here } break; } }