最好的分布式暴力对抗措施是什么?

发布于 2024-07-12 21:41:31 字数 1706 浏览 45 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

风吹雪碎 2024-07-19 21:41:36

免责声明:我在一家双因素公司工作,但我不是来插嘴的。 以下是一些观察结果。

Cookie 可能会通过 XSS 和浏览器漏洞被窃取。 用户通常会更换浏览器或清除 cookie。

源 IP 地址同时是动态可变的和可欺骗的。

验证码很有用,但不能验证特定人员的身份。

多种方法可以成功组合,但良好的品味肯定是必要的。

密码复杂性很好,任何基于密码的东西都关键取决于密码是否具有足够的熵。 恕我直言,写在安全物理位置的强密码比内存中的弱密码更好。 人们知道如何评估纸质文档的安全性,比知道如何计算狗的名字用作三个不同网站的密码时的有效熵要好得多。 考虑让用户能够打印一大页或一小页,其中包含一次性使用密码。

像“你的高中吉祥物是什么”这样的安全问题大多是“你知道的东西”的另一种糟糕形式,其中大多数很容易猜到或完全在公共领域。

正如您所指出的,限制失败的登录尝试是防止暴力攻击和轻松 DoSing 帐户之间的权衡。 激进的锁定策略可能反映出对密码熵缺乏信心。

无论如何,我个人并不认为在网站上强制密码过期有什么好处。 攻击者一旦获得您的密码,他就可以更改密码并像您一样轻松地遵守该策略。 也许一个好处是,如果攻击者更改了帐户密码,用户可能会更快注意到。 如果在攻击者获得访问权限之前以某种方式通知用户,那就更好了。 诸如“自上次登录以来尝试失败 N 次”之类的消息在这方面很有用。

最好的安全性来自于第二个身份验证因素,它相对于第一个身份验证因素是带外的。 就像你说的,“你拥有的东西”中的硬件令牌很棒,但许多(不是全部)都有与其分发相关的真正管理开销。 我不知道有任何适合网站的生物识别“你是谁”解决方案。 一些双因素解决方案与 openid 提供商合作,一些具有 PHP/Perl/Python SDK。

Disclaimer: I work for a two-factor company, but am not here to plug it. Here're some observations.

Cookies can be stolen with XSS and browser vulns. Users commonly change browsers or clear their cookies.

Source IP addresses are simultaneously dynamically variable and spoofable.

Captcha is useful, but doesn't authenticate a specific human.

Multiple methods can be combined successfully, but good taste is certainly in order.

Password complexity is good, anything password-based critically depends on passwords having sufficient entropy. IMHO, a strong password written down in a secure physical location is better than a weak password in memory. People know how to evaluate the security of paper documents much better than they know how to figure the effective entropy in their dog's name when used as a password for three different websites. Consider giving users the ability to print out a big or small page full of one-time use pass codes.

Security questions like "what was your high-school mascot" are mostly another lousy form of "something you know", most of them are easily guessable or outright in the public domain.

As you noted, throttling back failed login attempts is a trade-off between preventing brute-force attacks and ease of DoSing an account. Aggressive lockout policies may reflect a lack of confidence in password entropy.

I personally don't see the the benefit to enforcing password expiration on a website anyway. Attacker gets your password once, he can change it then and comply with that policy just as easily as you can. Perhaps one benefit is that the user might notice sooner if the attacker changes the account password. Even better would be if the the user were somehow notified before the attacker gained access. Messages like "N failed attempts since last login" are useful in this respect.

The best security comes from a second factor of authentication which is out-of-band relative to the first. Like you said, hardware tokens in the "something you have" are great, but many (not all) have real admin overhead associated with their distribution. I don't know of any biometric "something you are" solutions good for websites. Some two-factor solutions work with openid providers, some have PHP/Perl/Python SDKs.

雪化雨蝶 2024-07-19 21:41:36

Looks like you are trying to defend against slow distributed brute force. Not that much you can do about it. We are using a PKI and no password logins. It helps, but if your clients chance workstations every once in a while, this is not very applicable.

梦年海沫深 2024-07-19 21:41:36

将Jens的方案总结为伪状态转换图/规则库:

  1. 用户+密码-> 输入
  2. 用户+!密码-> 被拒绝的
  3. 用户 +known_IP(用户) -> 前门,// 永不限制
  4. user +unknown_IP(user) -> catflap
  5. (#denied > n) 来自 catflaps(site) -> throttle catflaps(site) // 让机器人慢下来
  6. catflap +throttle + 密码 + 验证码 -> 条目 // 人类仍然欢迎
  7. catflap +throttle + 密码 + !captcha -> 拒绝 // 机器人的正确猜测

观察:

  • 永远不要关闭前门。 埃尔博尼亚州警察在您家中拥有您的计算机,但无法审问您。 暴力破解是计算机上一种可行的方法。
  • 如果您提供“忘记密码?” 链接,那么您的电子邮件帐户就会成为攻击面的一部分。

这些观察结果涵盖了与您试图应对的攻击不同类型的攻击。

To summarize Jens' scheme into a pseudo state transition diagram/rulebase:

  1. user + password -> entry
  2. user + !password -> denied
  3. user + known_IP(user) -> front door, // never throttle
  4. user + unknown_IP(user) -> catflap
  5. (#denied > n) via catflaps(site) -> throttle catflaps(site) // slow the bots
  6. catflap + throttle + password + captcha -> entry // humans still welcome
  7. catflap + throttle + password + !captcha -> denied // a correct guess from a bot

Observations:

  • Never throttle the front door. The Elbonian state police have your computer, in your house, but are unable to interrogate you. Brute force is a viable approach from your computer.
  • If you provide a "Forgetten your password?" link, then your email account becomes part of the attack surface.

These observations cover a different type of attack to the ones you are trying to counter.

哥,最终变帅啦 2024-07-19 21:41:36
  1. 在输入普通密码之前要求输入一次性密码怎么样? 这将非常明显地表明有人在有很多机会猜测主密码之前就在进行攻击?

  2. 保持登录失败的全局计数/率 - 这是攻击的指标 - 在攻击期间对登录失败更加严格,例如更快地禁止 IP。

  1. What about requiring a one-time-password before entering their normal password? That would make it very obvious that someone was attacking before they got many opportunities to guess the main password?

  2. Keep a global count/rate of login failures - this is the indicator for an attack - during an attack be stricter about login failures e.g. ban IPs more rapidly.

萧瑟寒风 2024-07-19 21:41:36

我不相信有一个完美的答案,但我倾向于在检测到攻击时试图迷惑机器人的基础上接近它。

我首先想到的是:

切换到另一个登录屏幕。 它有多个用户名和密码空白,这些空白确实出现了,但只有其中一个位于正确的位置。 字段名称是随机——会话密钥与登录屏幕一起发送,然后服务器可以找出哪些字段是什么。 无论成功或失败,它都会被丢弃,因此您无法尝试重放攻击 - 如果您拒绝密码,它们将获得一个新的会话 ID。

任何在错误字段中提交数据的表单都被假定为来自机器人——登录失败,期间,并且该 IP 被限制。 确保随机字段名称永远不会与合法字段名称匹配,这样使用记住密码的东西的人就不会被误导。

接下来,我们来看看不同类型的验证码:您有一系列不会给人类带来问题的问题。 然而,它们不是是随机的。 当攻击开始时,每个人都会遇到问题#1。 一小时后,问题#1 被丢弃,不再使用,每个人都会收到问题#2,依此类推。

由于问题的一次性性质,攻击者无法尝试下载数据库以放入他的机器人中。 他必须在一小时内向他的僵尸网络发送新指令才能有能力做任何事情。

I don't believe there is a perfect answer but I would be inclined to approach it on a basis of trying to confound the robots if an attack is sensed.

Off the top of my mind:

Switch to an alternate login screen. It has multiple username and password blanks which really do appear but only one of them is in the right place. The field names are RANDOM--a session key is sent along with the login screen, the server can then find out what fields are what. Succeed or fail it's then discarded so you can't try a replay attack--if you reject the password they get a new session ID.

Any form that is submitted with data in a wrong field is assumed to be from a robot--the login fails, period, and that IP is throttled. Make sure the random field names never match the legit field names so someone using something that remembers passwords isn't mislead.

Next, how about a different sort of captcha: You have a series of questions that won't cause problems for a human. However, they are NOT random. When the attack starts everyone is given question #1. After an hour question #1 is discarded, never to be used again and everyone gets question #2 and so on.

The attacker can't probe to download the database to put into his robot because of the disposable nature of the questions. He has to send new instructions out to his botnet within an hour to have any ability to do anything.

似狗非友 2024-07-19 21:41:36

我的最高建议是确保您让用户了解其帐户的错误登录尝试 -
如果用户有证据表明有人确实试图进入他们的帐户,他们可能会更加重视密码的强度。

事实上,我发现有人侵入了我兄弟的 myspace 帐户,因为他们试图进入我为他设置的 gmail 帐户,并使用“通过电子邮件重置我的密码”功能……该功能进入了我的收件箱。

My highest recommendation is to simply make sure that you keep users informed of bad login attempts to their accounts--
Users will likely take the strength of their password much more seriously if they are presented with evidence that somebody is actually trying to get into their account.

I actually caught somebody that hacked into my brother's myspace account because they had tried to get into the gmail account I setup for him and used the 'reset my password by email' feature... which went to my inbox.

蓦然回首 2024-07-19 21:41:36

您还可以根据用户密码的强度进行限制。

当用户注册或更改密码时,您会计算其密码的强度等级,例如 1 到 10 之间。

诸如“password”之类的内容得分为 1,而“c6eqapRepe7et*Awr@ch”可能得分为 9 或 10,得分越高节流启动所需的时间越长。

You could also throttle based on the strength of a users password.

When a user registers or changes their password you calculate a strength rating for their password, say between 1 and 10.

Something like "password" scores a 1 whereas "c6eqapRepe7et*Awr@ch" might score a 9 or 10 and the higher the score the longer it takes for throttling to kick in.

暗藏城府 2024-07-19 21:41:36

由于有些人将验证码作为后备人类机制,因此我添加了一个早期的 StackOverflow 问题和关于验证码有效性的线程。

reCaptcha 是否已被破解/黑客攻击/OCR 识别/击败/损坏?< /a>

使用验证码不会限制对限制和其他建议的改进,但我认为包含验证码作为后备的答案数量应该考虑那些想要破坏安全的人可以使用的基于人的方法。

Since several folks included CAPTCHA as a fallback human mechanism, I'm adding an earlier StackOverflow question and thread on CAPTCHA's effectiveness.

Has reCaptcha been cracked / hacked / OCR’d / defeated / broken?

Using CAPTCHA doesn't limit improvements from your throttling and other suggestions, but I think the number of answers that include CAPTCHA as a fallback should consider the human-based methods available to people looking to break security.

一袭水袖舞倾城 2024-07-19 21:41:36

当我问这个问题时,我通常听到的第一个答案是更改端口,但忘记这一点,只需禁用 IPv4 即可。 如果您只允许来自 IPv6 网络的客户端,您将不再祈求简单的网络扫描,攻击者将诉诸 DNS 查找。 不要在与您的 Apache(AAAA)/Sendmail(MX->AAAA)/您向所有人发出的内容(AAAA)相同的地址上运行。 确保您的区域不能被 xferd,等等,您允许任何人下载您的区域吗?

如果机器人发现您的服务器设置了新的主机名,只需在您的主机名前面添加一些乱码,然后更改您的地址即可。 保留旧名称,甚至设置**蜜罐名称,让僵尸网络超时。

** 测试您的反向(PTR)记录(在 ip6.arpa 下),看看它们是否可以用于在有记录的 /4 上归零 VS /4 上没有记录。 IE 通常,ip6.arpa 在一个地址中会有大约 32 个“.”,但尝试使用最后几个丢失的内容可能会避开有记录的网络块与其他没有记录的网络块。 如果更进一步,就可以跳过大部分地址空间。

在最坏的情况下,用户将不得不设置 IPv6 隧道,但他们并不需要通过 VPN 进入 DMZ……尽管有人想知道为什么这不是第一个选择。

Kerberos 也很酷,但恕我直言,LDAP 很糟糕(NISPlus 在技术上有什么问题?我读到 Sun 决定用户需要 LDAP,因此他们放弃了 NIS+)。 Kerberos 在没有 LDAP 或 NIS 的情况下也能正常工作,只需在主机上管理用户即可。 使用 Kerberos 可以为您提供易于使用(即使不是自动化)的 PKI。

The first answer I've usually heard when asking this question is to change ports, but forget about that and just disable IPv4. If you only allow clients from IPv6 networks you'r no longer pray for simple network scanning and attackers will resort to DNS lookups. Don't run on the same address as your Apache(AAAA)/Sendmail(MX->AAAA)/what have you given out to everybody(AAAA). Make sure your zone can't be xferd, wait you'r allowing your zone to be downloaded by anybody?

If the bots find your server setup new hostnames, just prepend some gibberish to your hostnames, and change your address. Leave the old names and even setup **honeypot names for the bot net to timeout on.

** Test your reverse(PTR) records(under ip6.arpa.) to see if they can be used to zero in on /4's that have records VS /4s that don't. I.E. Typically ip6.arpa would have ~32 "."s in an address but trying with the last few missing might elude the network blocks that have records VS others that don't. If you take that further it becomes possible to skip large portions of the address space.

In the worst case users will have to setup an IPv6 tunnel, it's not like they'd have to go as far as VPNing into a DMZ... Though one wonders why that's not the first option.

Also Kerberos is cool, but IMHO LDAP blows(What's technically wrong with NISPlus? I've read that Sun decided that users wanted LDAP and because of this they dropped NIS+). Kerberos does work fine without LDAP or NIS, just have to manage users on a host by host basis. Using Kerberos gives you an easy to use, if not automated, PKI.

软甜啾 2024-07-19 21:41:36

虽然有点晚了,但我在想,假设一个困难的情况 - 攻击者使用大量随机 IP、随机用户名和从 10,000 个最流行的列表中选择的随机密码。

您可以做的一件事是,特别是如果系统似乎受到攻击,因为系统上有很多错误的密码尝试,特别是如果密码是低熵的,那就是问一个次要问题,例如您父母的名字是什么。 如果攻击者尝试使用密码“password1”攻击一百万个帐户,他们很有可能会得到很多,但他们也获得正确名称的几率将大大降低成功率。

Bit late here but I was thinking, assuming a hard case - the attacker uses a lot of random IPs, random user names and a random password selected from say a list of the 10,000 most popular.

One thing you could do, especially if the system seems under attack in that there are a lot of wrong password attempts on the system and especially if the password is low entropy is to ask a secondary question like what are your parents first names, for example. If an attacker hits a million accounts trying the password 'password1' there's a good chance they'll get a lot but their odds of also getting the names right would reduce successes dramatically.

晌融 2024-07-19 21:41:35

身份验证包含三个因素:

  1. 用户知道某事(即密码)
  2. 用户拥有某事(即密钥卡)
  3. 用户是某事(即视网膜扫描)

通常,网站仅执行策略#1。 即使大多数银行也只执行策略 1。他们反而依赖于“知道其他东西”的方法来进行双因素身份验证。 (即:用户知道他们的密码和母亲的婚前姓名。)如果可以的话,添加第二个身份验证因素的方法并不太困难。

例如,如果您可以生成大约 256 个随机字符,则可以将其构建在 16×16 表格中,然后要求用户在单元格 A-14 的表格中提供值。 当用户注册或更改密码时,请将表格交给他们并告诉他们打印并保存。

这种方法的困难在于,当用户忘记密码时(他们会忘记密码),您不能只提供标准的“回答这个问题并输入新密码”,因为这也容易受到暴力破解。 此外,您无法重置它并向他们发送新的电子邮件,因为他们的电子邮件也可能受到损害。 (参见:Makeuseof.com 和他们被盗的域名。)

另一个想法(涉及小猫)是 BOA 所称的 SiteKey(我相信他们已将这个名称注册为商标)。 简而言之,您让用户在注册时上传图像,当他们尝试登录时,要求他们从 8 或 15(或更多)随机图像中选择图像。 因此,如果用户上传他们的小猫的照片,理论上只有他们确切地知道从所有其他小猫(或花或其他什么)中哪张照片是他们的。 这种方法唯一真正的漏洞是中间人攻击。

另一个想法(虽然没有小猫)是跟踪用户访问系统的 IP,并要求他们在从他们不知道的地址登录时执行额外的身份验证(验证码、选择一只小猫、从该表中选择一个密钥)以前没有。 此外,与 GMail 类似,允许用户查看他们最近从哪里登录。

编辑,新想法:

验证登录尝试的另一种方法是检查用户是否来自您的登录页面。 您无法检查引荐来源网址,因为它们很容易被伪造。 您需要的是当用户查看登录页面时在 _SESSION 变量中设置一个密钥,然后在提交登录信息时检查以确保该密钥存在。 如果机器人没有从登录页面提交,它将无法登录。 您还可以通过在该过程中使用 javascript 来实现这一点,或者使用它来设置 cookie,或者在加载表单后向表单添加一些信息。 或者,您可以将表单拆分为两个不同的提交(即,用户输入用户名,提交,然后在新页面上输入密码并再次提交。)

在这种情况下,密钥是最重要的方面。 生成它们的常见方法是用户数据、IP 和提交时间的某种组合。

There are three factors of authentication:

  1. A user knows something (ie, a password)
  2. A user has something (ie, a key fob)
  3. A user is something (ie, retina scan)

Usually, websites only enforce policy #1. Even most banks only enforce policy 1. They instead rely on a "knows something else" approach to two-factor authentication. (IE: A user knows their password and their mother's maiden name.) If you are able, a way to add in a second factor of authentication is not too difficult.

If you can generate around 256 characters of randomness, you could structure that in a 16×16 table, and then ask the user to give you the value in the table of cell A-14, for example. When a user signs up or changes their password, give them the table and tell them to print it off and save it.

The difficulty with that approach is that when a user forgets their password, as they will, you can't just offer the standard "answer this question and put in a new password", since that's vulnerable to brute-force as well. Also, you can't reset it and email them a new one, since their email could be compromised as well. (See: Makeuseof.com and their stolen domain.)

Another idea (which involves kittens), is what BOA calls SiteKey (I believe they trademarked the name). Briefly, you have the user upload an image when they register, and when they attempt to login, ask them to pick their image out of 8 or 15 (or more) random ones. So, if a user uploads a picture of their kitten, theoretically only they know exactly which picture is theirs out of all the other kittens (or flowers or whatever). The only real vunerability this approach has is the man-in-the-middle attack.

One more idea (no kittens though), is to track IPs that users access the system with, and require them to perform additional authentication (captcha , pick a kitty, pick a key from this table) when they log in from an address they haven't before. Also, similar to GMail, allow the user to view where they have logged in from recently.

Edit, New Idea:

Another way of validating login attempts is to check whether or not the user has come from your login page. You can't check referrers, since they can be easily faked. What you need is to set a key in the _SESSION var when the user views the login page, and then check to make sure that key exists when they submit their login information. If bot does not submit from the login page, it will not be able to login. You can also facilitate this by involving javascript in the process, either by using it to set a cookie, or adding some information to the form after it has loaded. Or, you can split the form up into two different submits (ie, the user enters their username, submits, then on a new page enters their password and submit again.)

The key, in this case, is the most important aspect. A common method of generating them is some combination of the user's data, their IP, and the time it was submitted.

娇女薄笑 2024-07-19 21:41:35

我之前曾在 How can Ithrottle 回答过一个非常类似的问题PHP 中的用户登录尝试。 我将在这里重申建议的解决方案,因为我相信你们中的许多人会发现它对于查看一些实际代码很有用。 请记住,由于当今验证码破坏程序中使用的算法越来越准确,使用验证码可能不是最好的解决方案:

您不能简单地通过将限制链接到单个 IP 或用户名来防止 DoS 攻击。 天啊,使用这种方法你甚至无法真正阻止快速登录尝试。

为什么? 因为攻击可以跨越多个 IP 和用户帐户以绕过您的限制尝试。

我在其他地方看到过帖子,理想情况下您应该跟踪整个网站上所有失败的登录尝试并将它们与时间戳相关联,也许:

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;

根据决定某些延迟>总体给定时间内登录失败的次数。 您应该将此基于从 failed_logins 表中提取的统计数据,因为它会随着时间的推移而变化,具体取决于用户数量以及其中有多少人可以回忆(和输入)他们的信息密码。


10 failed attempts = 1 second
20 failed attempts = 2 seconds
30 failed attempts = reCaptcha

查询每次失败登录尝试的表,以查找给定时间段(例如 15 分钟)内失败登录的次数:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);

如果给定时间段内的尝试次数超过限制,则强制限制或强制所有用户登录使用验证码(即 reCaptcha),直到给定时间段内的失败尝试次数小于阈值。

// 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;
    }
}

在一定阈值下使用 reCaptcha 将确保最大限度地减少来自多个方面的攻击,并且普通站点用户不会因合法的失败登录尝试而遇到明显的延迟。 我不能保证预防,因为验证码可以被破坏,这一点已经得到了扩展。 还有其他解决方案,也许是“命名这种动物”的变体,作为替代方案可以很好地发挥作用。

I had previously answered a very similar question over at How can I throttle user login attempts in PHP. I'll reiterate the proposed solution here as I believe many of you will find it informational and useful to see some actual code. Please bare in mind that using a CAPTCHA might not be the best solution due to the increasingly accurate algorithms being used in CAPTCHA busters nowadays:

You cannot simply prevent DoS attacks by chaining throttling down to a single IP or username. Hell, you can't even really prevent rapid-fire login attempts using this method.

Why? Because the attack can span multiple IPs and user accounts for the sake of bypassing your throttling attempts.

I have seen posted elsewhere that ideally you should be tracking all failed login attempts across the site and associating them to a timestamp, perhaps:

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;

Decide on certain delays based on the overall number of failed logins in a given amount of time. You should base this on statistical data pulled from your failed_logins table as it will change over time based on the number of users and how many of them can recall (and type) their password.


10 failed attempts = 1 second
20 failed attempts = 2 seconds
30 failed attempts = reCaptcha

Query the table on every failed login attempt to find the number of failed logins for a given period of time, say 15 minutes:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);

If the number of attempts over the given period of time is over your limit, either enforce throttling or force all user's to use a captcha (i.e. reCaptcha) until the number of failed attempts over the given time period is less than the threshold.

// 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;
    }
}

Using reCaptcha at a certain threshold would ensure that an attack from multiple fronts would be minimized and normal site users would not experience a significant delay for legitimate failed login attempts. I can't gaurantee prevention, as it's already been expanded upon that CAPTCHA's can be busted. There are alternative solutions, perhaps a variant of "Name this animal", which could work quite well as a substitute.

吖咩 2024-07-19 21:41:35

我想问你是否对这个问题做过成本效益分析? 听起来您正试图保护自己免受攻击者的攻击,该攻击者拥有足够的网络存在来猜测大量密码,每个 IP 可能发送 3-5 个请求(因为您已解除 IP 限制)。 这种攻击的成本(大约)是多少? 它是否比您要保护的帐户的价值更昂贵? 有多少庞大的僵尸网络想要您拥有的东西?

答案可能是否定的——但如果是的话,我希望您能从某种安全专业人士那里得到帮助; 编程技能(和 StackOverflow 分数)与安全知识没有很强的相关性。

I have to ask whether you've done cost-benefit analysis of this problem; it sounds like you're trying to protect yourself from an attacker who has enough web presence to guess a number of passwords, sending maybe 3-5 requests per IP (since you've dismissed IP throttling). How much (roughly) would that kind of attack cost? Is it more expensive than the value of the accounts you're trying to protect? How many gargantuan botnets want what you've got?

The answer might be no -- but if it is, I hope you're getting help from a security professional of some sort; programming skill (and StackOverflow score) do not correlate strongly to security know-how.

极度宠爱 2024-07-19 21:41:33

如果我正确理解暴力攻击的 MO,那么会连续尝试一个或多个用户名。

有两个建议我认为我还没有在这里看到:

  • 我一直认为标准做法是在每个用户每次错误登录后有一个短暂的延迟(一秒左右)。 这可以阻止暴力破解,但我不知道一秒的延迟可以阻止字典攻击多久。 (10,000 个单词的词典 == 10,000 秒 == 大约 3 小时。嗯。不够好。)
  • 与其在整个站点范围内减慢速度,为什么不进行用户名限制。 每次错误的尝试都会使节流阀变得越来越严厉(我想达到一个限制,这样真正的用户仍然可以登录)

编辑
回应有关用户名限制的评论:这是一个特定于用户名的限制,与攻击源无关。

如果用户名受到限制,那么即使是协调的用户名攻击(多 IP、每个 IP 单一猜测、相同用户名)也会被捕获。 即使攻击者可以在超时期间自由尝试另一个用户/通行证,单个用户名也会受到限制。

从攻击者的角度来看,在超时期间,您可能能够第一次猜测 100 个密码,并很快发现每个帐户有一个错误的密码。 您可能只能对同一时间段进行 50 秒的猜测。

从用户帐户的角度来看,即使猜测来自多个来源,仍然需要相同的平均猜测次数来破解密码。

对于攻击者来说,破坏 100 个帐户与破坏 1 个帐户的工作充其量是相同的,但由于您没有在整个站点范围内进行限制,因此您可以很快地加大限制。

额外改进:

  • 检测猜测多个帐户的 IP - 408 请求超时
  • 检测猜测同一帐户的 IP - 大量(例如 100)次猜测后出现 408 请求超时。

UI 想法(可能不适合这种情况),也可能会完善上述内容:

  • 如果您可以控制密码设置,则向用户显示 他们的密码有多强鼓励他们选择一个更好的密码。
  • 如果您控制登录页面,在对单个用户名进行少量(例如 10 次)猜测后,提供验证码。

If I understand the MO of brute force attacks properly, then one or more usernames are tried continuously.

There are two suggestions which I don't think I've seen yet here:

  • I always thought that the standard practice was to have a short delay (a second or so) after each wrong login for every user. This deters brute-force, but I don't know how long a one second delay would keep a dictionary attack at bay. (dictionary of 10,000 words == 10,000 seconds == about 3 hours. Hmm. Not good enough.)
  • instead of a site-wide slow down, why not a user-name throttle. The throttle becomes increasingly harsh with each wrong attempt (up to a limit, I guess so the real user can still login)

Edit:
In response to comments on a username throttle: this is a username specific throttle without regard to the source of the attack.

If the username is throttled, then even a coordinated username attack (multi IP, single guess per IP, same username) would be caught. Individual usernames are protected by the throttle, even if the attackers are free to try another user/pass during the timeout.

From an attackers point of view, during the timeout you may be able to take a first time guess at 100 passwords, and quickly discover one wrong password per account. You may only be able to make a 50 second guesses for the same time period.

From a user account point of view, it still takes the same average number of guesses to break the password, even if the guesses are coming from multiple sources.

For the attackers, at best, it will be the same effort to break 100 accounts as it would 1 account, but since you're not throttling on a site wide basis, you can ramp up the throttle quite quickly.

Extra refinements:

  • detect IPs that are guessing multiple accounts - 408 Request Timeout
  • detect IPs that are guessing the same account - 408 Request Timeout after a large (say 100) number of guesses.

UI ideas (may not be suitable in this context), which may also refine the above:

  • if you are in control of the password setting, then showing the user how strong their password is encourages them to pick a better one.
  • if you are in control of the login page, after a small (say 10) number of guesses of a single username, offer a CAPTCHA.
差↓一点笑了 2024-07-19 21:41:32

几个简单的步骤:

将某些常见用户名列入黑名单,并将其用作蜜罐。 管理员、访客等...不要让任何人使用这些名称创建帐户,因此,如果有人尝试登录它们,您就知道有人在做不应该做的事情。

确保网站上拥有实权的任何人都拥有安全密码。 要求管理员/版主使用更长的密码,其中包含字母、数字和符号。 拒绝普通用户提供的简单密码并提供解释。

您可以做的最简单的事情之一就是告诉人们何时有人尝试登录他们的帐户,并为他们提供一个链接以报告该事件(如果不是他们)。
他们登录时会收到一条简单的消息,例如“有人试图在周三凌晨 4:20 登录您的帐户等等。如果这不是您本人,请点击此处。” 它可以让您保留一些有关攻击的统计数据。 如果您发现欺诈性访问突然增加,您可以加强监控和安全措施。

A few simple steps:

Blacklist certain common usernames, and use them as a honeypot. Admin, guest, etc... Don't let anyone create accounts with these names, so if someone does try to log them in you know it's someone doing something they shouldn't.

Make sure anyone who has real power on the site has a secure password. Require admins/ moderators to have longer passwords with a mix of letters, numbers and symbols. Reject trivially simple passwords from regular users with an explanation.

One of the simplest things you can do is tell people when someone tried to log into their account, and give them a link to report the incident if it wasn't them.
A simple message when they log in like "Someone tried to log into your account at 4:20AM Wednesday blah blah. Click here if this wasn't you." It lets you keep some statistics on attacks. You can step up monitoring and security measures if you see that there's a sudden increase in fraudulent accesses.

陪你到最终 2024-07-19 21:41:31

将原始帖子中的方法 3 和方法 4 组合成一种“模糊”或动态白名单,然后 - 这就是技巧 - 不阻止非白名单 IP,只是将它们限制在地狱中并返回

请注意,此措施旨在阻止这种非常特定类型的攻击。 当然,在实践中,它可以与其他最佳实践方法结合起来进行身份验证:固定用户名限制、每个 IP 限制、代码强制的强密码策略、不受限制的 cookie 登录、在保存之前对所有密码等效项进行哈希处理,从不使用安全问题等。

有关攻击场景的假设

如果攻击者的目标是可变用户名,则我们的用户名限制不会触发。 如果攻击者使用僵尸网络或访问较大的IP范围,我们的IP限制就无能为力。 如果攻击者预先抓取了我们的用户列表(通常可以在开放注册 Web 服务上进行),我们将无法根据“未找到用户”错误的数量来检测正在进行的攻击。 如果我们在系统范围内(所有用户名、所有 IP)实施限制性限制,则任何此类攻击都将在攻击持续时间加上限制期间对我们的整个网站进行 DoS。

所以我们需要做点别的事情。

对策的第一部分:白名单

我们可以相当确定的是,攻击者无法检测并动态欺骗我们数千名用户 (+) 的 IP 地址。 这使得白名单变得可行。 换句话说:对于每个用户,我们存储用户之前(最近)登录的(散列)IP 列表。

因此,我们的白名单方案将充当锁定的“前门”,用户必须在其中从他公认的“好”IP 之一连接才能登录。 对这个“前门”进行暴力攻击实际上是不可能的(+)。

(+) 除非攻击者“拥有”服务器、我们所有用户的盒子或连接本身——在这些情况下,我们不再有“身份验证”问题,我们有一个真正的特许经营规模的拉动-plug FUBAR情况

对策的第二部分:对无法识别的IP进行系统范围的限制

为了使白名单适用于开放注册的Web服务,用户可以在其中切换计算机经常和/或从动态 IP 地址连接,我们需要为从无法识别的 IP 地址连接的用户保持“猫门”打开。 诀窍是设计这扇门,让僵尸网络陷入困境,并让合法用户尽可能少地受到干扰。

在我的方案中,这是通过设置未经批准的 IP 在 3 小时内尝试登录失败的非常最大次数来实现的(使用更短或更长的时间段可能更明智,具体取决于服务类型),并使该限制全局,即。 对于所有用户帐户。

使用此方法,即使是缓慢的(两次尝试之间 1-2 分钟)的暴力破解也能快速有效地被检测到并阻止。 当然,非常慢的强力攻击仍然可能不会被注意到,但是太慢的速度会破坏强力攻击的真正目的。

我希望通过这种限制机制实现的是,如果达到最大限制,我们的“猫门”会关闭一段时间,但我们的前门仍然对通过常规方式连接的合法用户开放:

  • 通过从以下之一连接 :他们认可的 IP
  • 或通过使用持久登录 cookie(从任何地方)

在攻击期间受影响的唯一合法用户 - 即。 当限制被激活时 - 没有持久登录 cookie 的用户从未知位置或使用动态 IP 登录。 这些用户将无法登录,直到限制消失(如果攻击者在限制下仍保持僵尸网络运行,这可能需要一段时间)。

为了让这一小部分用户能够挤过原本密封的猫门,即使机器人仍在努力敲打它,我也会使用带有验证码的“备份”登录表单。 因此,当您显示“抱歉,但您目前无法从此 IP 地址登录”消息时,请添加一个链接,其中显示“安全备份登录 - 仅限人类(机器人:不说谎< /em>)”。 开个玩笑吧,当他们点击该链接时,给他们一个经过 reCAPTCHA 验证的登录表单,可以绕过站点范围的限制。 这样,如果他们是人类并且知道正确的登录名+密码(并且能够读取验证码),他们将永远被拒绝服务,即使他们从未知主机连接并且不使用自动登录 cookie。

哦,只是澄清一下:由于我确实认为验证码通常是邪恶的,因此“备份”登录选项在限制处于活动状态时才会出现。

不可否认,像这样的持续攻击仍然会构成一种形式的 DoS 攻击,但在所描述的系统到位的情况下,它只会影响我怀疑的一小部分用户,即不使用该服务的人。 “记住我”cookie 并且在攻击发生时恰好登录并且没有从任何常用 IP 登录并且无法读取验证码。 只有那些能够对所有这些标准说“不”的人 - 特别是机器人和非常不幸的残疾人 - 才会在机器人攻击期间被拒绝。

编辑:实际上,我想到了一种方法,即使是验证码挑战的用户也可以在“锁定”期间通过:代替或作为备份验证码登录的补充,为用户提供一个选项,将一次性的、用户特定的锁定代码发送到他的电子邮件,然后他可以使用该代码来绕过限制。 这绝对超出了我的“烦恼”阈值,但由于它仅用作一小部分用户的最后手段,并且由于它仍然优于被锁定在您的帐户之外,因此这是可以接受的。

(另外,请注意,如果攻击比我在这里描述的令人讨厌的分布式版本更不复杂,则不会发生这种情况。如果攻击仅来自几个 IP 或者仅来自击中几个用户名,它会更早地受到阻碍,并且不会全站点范围的后果)


所以,这就是我将在我的身份验证库中实施的对策,一旦我确信它是合理的,而且我没有错过任何更简单的解决方案。 事实是,在安全方面有很多微妙的方法可以做错事情,而且我不会避免做出错误的假设或无可救药的有缺陷的逻辑。 所以,任何和所有的反馈、批评和改进、微妙之处等都受到高度赞赏。

Combining methods 3 and 4 from the original post into a kind of 'fuzzy' or dynamic whitelist, and then - and here's the trick - not blocking non-whitelisted IPs, just throttling them to hell and back.

Note that this measure is only meant to thwart this very specific type of attack. In practice, of course, it would work in combination with other best-practices approaches to auth: fixed-username throttling, per-IP throttling, code-enforced strong password policy, unthrottled cookie login, hashing all password equivalents before saving them, never using security questions, etc.

Assumptions about the attack scenario

If an attacker is targeting variable usernames, our username throttling doesn't fire. If the attacker is using a botnet or has access to a large IP range, our IP throttling is powerless. If the attacker has pre-scraped our userlist (usually possible on open-registration web services), we can't detect an ongoing attack based on number of 'user not found' errors. And if we enforce a restrictive system-wide (all usernames, all IPs) throttling, any such attack will DoS our entire site for the duration of the attack plus the throttling period.

So we need to do something else.

The first part of the countermeasure: Whitelisting

What we can be fairly sure of, is that the attacker is not able to detect and dynamically spoof the IP addresses of several thousand of our users(+). Which makes whitelisting feasible. In other words: for each user, we store a list of the (hashed) IPs from where the user has previously (recently) logged in.

Thus, our whitelisting scheme will function as a locked 'front door', where a user must be connected from one of his recognized 'good' IPs in order to log in at all. A brute-force attack on this 'front door' would be practically impossible(+).

(+) unless the attacker 'owns' either the server, all our users' boxes, or the connection itself -- and in those cases, we no longer have an 'authentication' issue, we have a genuine franchise-sized pull-the-plug FUBAR situation

The second part of the countermeasure: System-wide throttling of unrecognized IPs

In order to make a whitelist work for an open-registration web service, where users switch computers frequently and/or connect from dynamic IP addresses, we need to keep a 'cat door' open for users connecting from unrecognized IPs. The trick is to design that door so botnets get stuck, and so legitimate users get bothered as little as possible.

In my scheme, this is achieved by setting a very restrictive maximum number of failed login attempts by unapproved IPs over, say, a 3-hour period (it may be wiser to use a shorter or longer period depending on type of service), and making that restriction global, ie. for all user accounts.

Even a slow (1-2 minutes between attempts) brute force would be detected and thwarted quickly and effectively using this method. Of course, a really slow brute force could still remain unnoticed, but too slow speeds defeat the very purpose of the brute force attack.

What I am hoping to accomplish with this throttling mechanism is that if the maximum limit is reached, our 'cat door' slams closed for a while, but our front door remains open to legitimate users connecting by usual means:

  • Either by connecting from one of their recognized IPs
  • Or by using a persistent login cookie (from anywhere)

The only legitimate users who would be affected during an attack - ie. while the throttling was activated - would be users without persistent login cookies who were logging in from an unknown location or with a dynamic IP. Those users would be unable to login until the throttling wore off (which could potentially take a while, if the attacker kept his botnet running despite the throttling).

To allow this small subset of users to squeeze through the otherwise-sealed cat door, even while bots were still hammering away at it, I would employ a 'backup' login form with a CAPTCHA. So that, when you display the "Sorry, but you can't login from this IP address at the moment" message, include a link that says "secure backup login - HUMANS ONLY (bots: no lying)". Joke aside, when they click that link, give them a reCAPTCHA-authenticated login form that bypasses the site-wide throttling. That way, IF they are human AND know the correct login+password (and are able to read CAPTCHAs), they will never be denied service, even if they are connecting from an unknown host and not using the autologin cookie.

Oh, and just to clarify: Since I do consider CAPTCHAs to be generally evil, the 'backup' login option would only appear while throttling was active.

There is no denying that a sustained attack like that would still constitute a form of DoS attack, but with the described system in place, it would only affect what I suspect to be a tiny subset of users, namely people who don't use the "remember me" cookie AND happen to be logging in while an attack is happening AND aren't logging in from any of their usual IPs AND who can't read CAPTCHAs. Only those who can say no to ALL of those criteria - specifically bots and really unlucky disabled people - will be turned away during a bot attack.

EDIT: Actully, I thought of a way to let even CAPTCHA-challenged users pass through during a 'lockdown': instead of, or as a supplement to, the backup CAPTCHA login, provide the user with an option to have a single-use, user-specific lockdown code sent to his email, that he can then use to bypass the throttling. This definitely crosses over my 'annoyance' threshold, but since it's only used as a last resort for a tiny subset of users, and since it still beats being locked out of your account, it would be acceptable.

(Also, note that none of this happens if the attack is any less sophisticated than the nasty distributed version I've described here. If the attack is coming from just a few IPs or only hitting a few usernames, it will be thwarted much earlier, and with no site-wide consequences)


So, that is the countermeasure I will be implementing in my auth library, once I'm convinced that it's sound and that there isn't a much simpler solution that I've missed. The fact is, there are so many subtle ways to do things wrong in security, and I'm not above making false assumptions or hopelessly flawed logic. So please, any and all feedback, criticism and improvements, subtleties etc. are highly appreciated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文