什么是最好的分布式蛮力对策?

首先,介绍一些背景知识: 我正在为 CodeIgniter 实现一个 auth + auth 系统,这已经不是什么秘密了,到目前为止,我正在取得胜利(可以这么说)。但是我遇到了一个非常重要的挑战(大多数 auth 库完全忽略了这个挑战,但是我坚持正确地处理它) : 如何智能地处理 大规模、分布式、可变用户名的暴力攻击

我知道所有常见的把戏:

  1. 限制每个 IP/主机的失败尝试次数并拒绝违规者访问(例如: Fail2Ban)——由于僵尸网络已经变得更加智能,这已经不再有效
  2. 将以上内容与 已知“坏”IP/主机的黑名单(例如 DenyHosts)结合起来——后者依赖于价格下跌1英镑的僵尸网络 但他们越来越不喜欢了
  3. IP/host whitelists 结合了传统的 auth (遗憾的是,对于动态 IP 用户和大多数网站的高流量来说毫无用处)
  4. 在 N 分钟/小时内将失败尝试的 全场限制设置为 # ,然后在 N 分钟/小时内限制(暂停)所有登录尝试数分钟/小时(问题是 DoS 攻击你成为僵尸网络孩子的游戏)
  5. 强制性 数字签名(公钥证书)或 RSA 硬件令牌适用于所有没有登录/密码选项的用户(毫无疑问,这是一个坚如磐石的解决方案,但只适用于封闭的专用服务)
  6. 强制的 超强密码方案(例如 > 25个带有符号的无意义字符——同样,对于普通用户来说太不切实际)
  7. 最后是 验证码(它在大多数情况下都可以工作,但是对于用户和 几乎毫无用处果断,足智多谋的袭击者来说很烦人)

这些只是理论上可行的想法。有 很多的垃圾想法,吹大了网站的开放(例如,琐碎的 DoS 攻击)。我想要的是更好的东西。更好的意思是:

  • 它必须是安全的(+)对 DoS 和暴力攻击,并没有引入任何新的漏洞,可能允许一个稍微鬼鬼祟祟的机器人继续在雷达下运作

  • 必须是自动的。如果它需要人工操作员来验证每个登录或监视可疑活动,那么在现实场景中将无法工作

  • 它必须是可行的主流网络使用(即。可由非程序员执行的高流量、高容量和开放注册)

  • 它不能阻碍用户体验到一个临时用户会感到烦恼或沮丧(并可能放弃网站)的地步

  • 它不能涉及小猫,除非他们是 非常非常安全小猫

(+) 我所说的“安全”,是指至少和偏执狂用户保密密码的能力一样安全

说来听听!你会怎么做?你知道一个我没有提到的最佳实践吗(哦,请说你知道) ?我承认我确实有自己的想法(把3和4的想法结合起来) ,但是在让自己难堪之前,我还是让真正的专家来说吧; -)

18132 次浏览

看起来你在试图防御 缓慢分布的蛮力。你也无能为力。我们使用 PKI,没有密码登录。这是有帮助的,但是如果你的客户每隔一段时间就换一次工作站,这就不太适用了。

  1. 在输入正常的密码之前要求输入一次性密码怎么样?这样就能很明显地看出有人在他们有很多机会猜到主密码之前就开始进行攻击了吗?

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

如果我正确地理解了暴力攻击的 MO,那么一个或多个用户名将被不断地尝试。

有两个建议,我想我还没有在这里看到:

  • 我一直认为,标准的做法是在每个用户每次错误登录后都有一个短暂的延迟(一秒左右)。这可以阻止暴力行为但我不知道一秒钟的延迟能让字典式攻击停留多久。(字典10,000字 = = 10,000秒 = = 约3小时。嗯。还不够好。)
  • 而不是整个网站的慢下来,为什么不用用户名节流阀。每次错误的尝试,节流阀都会变得越来越严厉(我猜这是一个限制,所以真正的用户仍然可以登录)

编辑 : 作为对用户名节流阀注释的回应: 这是一个用户名特定的节流阀,不考虑攻击的来源。

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

从攻击者的角度来看,在超时期间,您可以首次猜测100个密码,并迅速发现每个帐户一个错误的密码。在同一时间段内,你可能只能猜测50秒。

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

对于攻击者来说,最好的情况下,破坏100个帐户和破坏1个帐户的工作是一样的,但是因为您没有在整个站点范围内进行节流,所以可以很快地加快节流。

额外改进:

  • 检测猜测多个帐户的 IP-408请求超时
  • 检测正在猜测相同帐户的 IP-在大量(比如100次)猜测之后请求超时。

用户界面的想法(在这种情况下可能不合适) ,这也可以改进以上内容:

  • 如果您控制了密码设置,那么显示用户 他们的密码有多强将鼓励他们选择一个更好的密码设置。
  • 如果您控制了登录 呼叫,在对单个用户名进行少量(比如10次)猜测之后,提供一个 CAPTCHA。

认证有三个要素:

  1. 用户 知道的东西(即,一个密码)
  2. 一个用户 已经的东西(即,一个密钥卡)
  3. 用户 什么的(即视网膜扫描)

通常,网站只执行第一条规定。即使是大多数银行也只执行政策1。相反,它们依赖于“知道其他东西”的双因素身份验证方法。(例如: 用户知道自己的密码和母亲的娘家姓。)如果可以的话,添加第二个身份验证因素的方法并不太困难。

如果您可以生成大约256个字符的随机性,那么您可以在16 & times; 16表中构造它,然后要求用户为您提供单元格 A-14表中的值,例如。当用户注册或更改密码时,将表交给他们,并告诉他们打印出来并保存。

这种方法的困难之处在于,当用户忘记密码时(他们会忘记的) ,你不能只提供标准的“回答这个问题并输入一个新密码”,因为这也容易受到暴力的伤害。此外,你不能重置它,并电子邮件给他们一个新的,因为他们的电子邮件也可能被泄露。(参见: Makeuseof.com 及其被盗域名。)

另一个想法(涉及到小猫)是 BOA 所谓的 SiteKey (我相信他们注册了这个名字)。简而言之,让用户在注册时上传一张图片,当他们尝试登录时,要求他们从8张或15张(或更多)随机图片中挑选图片。所以,如果一个用户上传了一张他们小猫的照片,理论上只有他们知道哪张照片是他们的,而不是其他所有的小猫(或者花或者其他什么)。这种方法唯一真正的弱点是中间人攻击。

还有一个想法(虽然没有小猫) ,是跟踪用户访问系统的 IP,并要求他们执行额外的身份验证(验证码,选择一只小猫,从这张表中选择一个键) ,当他们从一个地址登录他们以前没有。此外,与 GMail 类似,允许用户查看他们最近登录的位置。

编辑,新想法:

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

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

我不相信有一个完美的答案,但我会倾向于接近它的基础上,试图混淆机器人,如果攻击是感觉。

我突然想到:

切换到备用登录屏幕。它有多个用户名和密码空白,这确实出现,但只有一个是在正确的地方。字段名称是 随机——会话密钥与登录屏幕一起发送,然后服务器可以找出哪些字段是什么。成功或失败,然后丢弃它,所以你不能尝试重播攻击-如果你拒绝密码,他们得到一个新的会话 ID。

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

接下来,来个不同类型的验证码怎么样: 你有一系列不会给人类带来麻烦的问题。但是,它们是 没有随机的。当攻击开始时,每个人都有第一个问题。一个小时后,第一个问题被丢弃,再也不会被使用,每个人都会得到第二个问题,以此类推。

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

将原帖中的方法3和方法4结合起来,形成一种“模糊”或动态白名单,然后——这里有一个诀窍—— 没有阻止非白名单 IP,只是扼杀他们的地狱和回来

请注意,这个措施是 只有意味着挫败这种非常具体的攻击类型。当然,在实践中,它将与其他最佳实践方法相结合: 固定用户名节流、每个 IP 节流、代码强制的强密码策略、不节流 cookie 登录、在保存之前对所有密码等价物进行哈希处理、从不使用安全问题等等。

关于攻击场景的假设

如果攻击者的目标是变量用户名,我们的用户名调节不会触发。如果攻击者正在使用僵尸网络或有权访问一个大的 IP 范围,我们的 IP 节流是无力的。如果攻击者已经预刮了我们的用户列表(通常可能在开放注册 Web 服务上) ,我们无法根据“用户未找到”错误的数量来检测正在进行的攻击。如果我们在整个系统范围内(所有用户名,所有 IP)实施限制,任何此类攻击都会在攻击持续时间加上限制期间拒绝我们的整个站点。

所以我们得做点别的。

对策的第一部分: 白名单

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

因此,我们的白名单方案将作为一个锁定的“前门”,其中一个用户必须连接到他的一个公认的“好”IP,以便登录。在这个“前门”上装一个穷举法几乎是不可能的(+)。

(+)除非攻击者“拥有”服务器、所有用户的盒子或连接本身——在这些情况下,我们不再有“身份验证”问题,我们有一个真正的特许权大小的拔插头 FUBAR 情况

对策的第二部分: 全系统节流 未经认可的 IP 地址

为了使白名单适用于开放注册的 Web 服务,其中用户经常切换计算机和/或从动态 IP 地址连接,我们需要为用户从未识别的 IP 连接打开一个“猫门”。诀窍在于设计这样的门,僵尸网络得到卡住,这样合法的用户得到困扰 越少越好

在我的方案中,这是通过设置一个 非常限制未经批准的 IP 在3小时内失败的登录尝试次数的最大值来实现的(根据服务类型使用更短或更长的时间可能更明智) ,然后设置这个限制 全球性的,即。所有用户帐户。

即使是一个缓慢的(1-2分钟之间尝试)蛮力将被检测和挫败迅速和有效地使用这种方法。当然,一个 abc0的蛮力仍然可以保持不被注意,但是太慢的速度破坏了穷举法的目的。

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

  • 要么从他们认可的 IP 地址连接
  • 或者使用持久登录 cookie (从任何地方)

在攻击中受到影响的唯一合法用户。而节流被激活-将是用户没有持久登录 cookie 谁登录从一个未知的位置或动态 IP。这些用户将无法登录,直到节流失效(这可能需要一段时间,如果攻击者保持他的僵尸网络运行,尽管节流)。

为了让这一小部分用户能够在机器人还在不断攻击的时候,通过另外密封的猫门,我会使用一个带有验证码的“备份”登录表单。因此,当您显示“对不起,但您不能从这个 IP 地址在此刻”的消息,包括一个链接,说: “ 安全备份登录-仅限人类(机器人: 不撒谎)”。玩笑归玩笑,当他们点击那个链接时,给他们一个 reCAPTCHA 认证的登录表单,绕过站点范围的节流。这样,如果他们是人类并且知道正确的登录 + 密码(并且能够读取 CAPTCHA) ,他们将被拒绝 永远不会服务,即使他们从一个未知的主机连接并且没有使用自动登录 cookie。

哦,只是澄清一下: 因为我确实认为验证码通常是邪恶的,’备份’登录选项将 只有出现 而节流是活跃的

不可否认,这样的持续攻击仍然会构成一种 DoS 攻击,但是随着所描述的系统的到位,它只会影响到我怀疑是用户的一小部分,即那些没有使用“记住我”cookie 的人,碰巧在攻击发生时正在登录,没有从他们通常的 IP 地址登录,也不能阅读验证码。只有那些能够对所有这些标准说不的人——特别是机器人和 真不走运残疾人——在机器人攻击期间才会被拒绝。

编辑: 事实上,我想到了一个方法,让即使是验证码挑战用户通过在一个“锁定”: 而不是,或作为一个补充,备份验证码登录,提供一个选项,有一个单一使用,用户特定的锁定代码发送到他的电子邮件,他可以用来绕过节流。这肯定超过了我的“烦恼”门槛,但是因为它只被用作一小部分用户的 最后的手段,而且因为它仍然比被锁在你的帐户之外要好,所以它是可以接受的。

(还要注意,如果攻击不如我在这里描述的讨厌的分布式版本复杂,就会发生 没有攻击。如果攻击来自几个 IP 地址或者只攻击了几个用户名,那么它将更早地被阻止,并且会产生 站点范围的后果)


因此,这就是我将在我的 auth 库中实现的对策,一旦我确信它是合理的,并且没有更简单的解决方案,我就错过了。事实上,在安全性方面有很多微妙的方法可以做错事情,我也不排除做出错误的假设或者错得离谱的逻辑。所以,请,任何和所有的反馈,批评和改进,微妙等高度赞赏。

一些简单的步骤:

列出一些常用的用户名,并把它们作为诱饵。行政人员,客人等等。.不要让任何人用这些名字创建帐户,所以如果有人试图登录他们,你知道这是有人做了一些他们不应该做的事情。

确保网站上任何有实权的人都有一个安全密码。要求管理员/版主使用混合了字母、数字和符号的较长密码。拒绝常规用户的简单密码,并附上说明。

你可以做的最简单的事情之一就是告诉人们当有人试图登录他们的账户时,如果不是他们,就给他们一个报告事件的链接。 一个简单的信息,当他们登录像“有人试图登录到你的帐户在星期三凌晨4:20等等。如果不是你,请点击这里”它可以让你保存一些攻击的统计数据。如果你发现欺诈性访问突然增加,你可以加强监控和安全措施。

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

  1. User + password-> entry 用户 + 密码-> 条目
  2. 用户 + ! 密码-> 拒绝
  3. User + known _ IP (user)-> front door,// never throttle
  4. 用户 + 未知 _ IP (用户)-> 活页夹
  5. (# 拒绝 > n)通过猫翼(网站)-> 节流猫翼(网站) // slow the bots
  6. 盖板 + 节流阀 + 密码 + 验证码-> 入口 // humans still welcome
  7. Captcha-> 拒绝 // a correct guess from a bot

观察结果:

  • 千万别踩前门的油门。埃尔波尼亚州警在你家里有你的电脑,但无法审问你。暴力是一种可行的方法,从您的计算机。
  • 如果你提供了一个“忘记你的密码?”链接,那么你的电子邮件帐户成为攻击面的一部分。

这些观察涵盖了与您试图反击的攻击不同类型的攻击。

我不得不问一下你是否已经解决了这个问题,听起来好像你是在试图保护自己免受一个攻击者的攻击,这个攻击者有足够的 web 成本-收益分析来猜测一些密码,每个 IP 可能发送3-5个请求(因为你已经排除了 IP 节流)。这种攻击大概要花多少钱?是不是比你想保护的账户的价值还要贵?有多少庞大的僵尸网络想要你所拥有的?

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

由于有几个人将 CAPTCHA 作为备用的人工机制,所以我添加了一个早期的 StackOverflow 问题和关于 CAPTCHA 有效性的线程。

ReCaptcha 被破解了/被黑了/被 OCR 了/被击败了/被破解了吗?

使用 CAPTCHA 并不会限制你的改进和其他建议,但是我认为包含 CAPTCHA 作为备用的答案的数量应该考虑那些希望破坏安全性的人们可以使用的基于人工的方法。

我的最高建议是简单地确保您 随时通知用户的错误登录尝试到他们的帐户- 如果有证据表明有人试图进入他们的账户,用户可能会更加重视他们的密码强度。

事实上,我发现有人黑进了我哥哥的 myspace 账户,因为他们试图进入我为他设置的 gmail 账户,并使用了“通过电子邮件重置我的密码”功能... ... 这个功能进入了我的收件箱。

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

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

源 IP 地址同时具有动态变化性和欺骗性。

验证码很有用,但不能鉴定特定的人类。

多种方法可以成功地结合在一起,但是好的品味当然是必要的。

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

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

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

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

最好的安全性来自第二个认证因素,它相对于第一个因素是带外的。正如您所说,“您拥有的东西”中的硬件令牌非常棒,但是许多(并非所有)硬件令牌都有与其分发相关的实际管理开销。我不知道任何生物识别“你是什么”的解决方案对网站有好处。有些双因素解决方案使用 openid 提供程序,有些使用 PHP/Perl/Python SDK。

我以前在 如何在 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 可以确保来自多个战线的攻击是 最小化,并且正常的站点用户不会因合法的失败登录尝试而经历显著的延迟。我不能保证预防,因为它已经扩展到验证码可以被终结。还有其他的解决方案,也许是“命名这种动物”的一个变体,它可以作为一个很好的替代品。

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

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

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

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

如果机器人发现你的服务器设置新的主机名,只是预先一些胡言乱语你的主机名,并改变你的地址。保留旧名称,甚至设置 * * 蜜罐名称,让 bot 网络超时。

* * 测试您的反向(PTR)记录(在 ip6.arpa 下)看看他们是否可以用来零对/4的记录 VS/4的,没有。也就是说,通常 ip6.arpa 应该在32英寸左右。“在一个地址中,但尝试与最后几个丢失可能会躲避有记录的网络块和其他没有记录的网络块。如果进一步深入,就有可能跳过大部分地址空间。

在最坏的情况下,用户将不得不设置一个 IPv6隧道,这并不像他们必须走到 VPNing 进入非军事区... 虽然有人想知道为什么这不是第一选择。

Kerberos 也很酷,但是恕我直言 LDAP 很烂(NISPlus 在技术上有什么问题?我读到 Sun 决定用户需要 LDAP,因此他们放弃了 NIS +)。Kerberos 在不使用 LDAP 或 NIS 的情况下工作得很好,只需要在主机基础上管理用户。使用 Kerberos 可以使您轻松使用 PKI (如果不是自动的话)。

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

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