如何在5次尝试失败时锁定用户帐户

时间:2010-12-27 22:49:39

标签: c# asp.net security locking

我有一个使用asp.net/C#开发的网站。我想在30分钟的时间内连续5次登录失败锁定用户帐户。我不想在数据库方面这样做。我知道这不是由会话变量完成的。我也不想使用cookie,因为用户可以轻松禁用cookie。

上述限制是否有完美的方法?

6 个答案:

答案 0 :(得分:7)

所以,没有cookie,没有会话数据,没有数据库。好的,但您需要将错误登录信息存储在某个地方。它必须是服务器端,因为您不能信任来自客户端的任何数据。所以这意味着一个数据库,一个文件,或一个神奇的帽子 - 但你需要在一个拥有这些数据的服务器上某些东西。我看到的选项:

  • 您自己的服务器
    • 数据库(我知道你说你不想要这个,但这是对的)
    • 文件
    • ...
  • 其他人的服务器
    • 数据库(Amazon SimpleDB?)
    • Google docs电子表格(但同样,数据库是您真正需要的)
    • S3或类似容器中的文件

你明白了。

答案 1 :(得分:6)

简短回答

跟踪给定IP地址的连续失败尝试次数以及任何给定的帐户ID(用户名/电子邮件)。使用包含IP,日期和帐户ID列的失败尝试表。限制一段时间内尝试登录的次数。

长答案

无法信任客户

你说你不能使用cookie或会话状态(由cookie保存)是正确的,因为攻击者可以简单地使用新cookie或者根本不使用任何尝试,从而欺骗你的系统。在任何情况下都不应该按照另一个答案的建议在客户端完成。永远不应该信任客户。但是你需要以某种方式跟踪攻击者,而不使用cookie的唯一可行方法就是通过他们的IP地址。

跟踪IP&限制尝试

IP地址可能是欺骗性的,但是无论如何,能够使用 en masse 的有动力的攻击者可能会使用更复杂的方法。您需要通过IP记录每次登录尝试,并在每次尝试时检查您的尝试日志是否在尝试帐户的最后N小时内包含至少5次或更多次尝试。您可能还希望限制来自给定IP的任何帐户的总尝试次数,以防止攻击者在几个小时的时间内在多个帐户上强制使用相同的组合。

锁定帐户

或者,您可以连续几次尝试将有问题的帐户锁定几个小时(虽然我反对这一点 - 您的用户永远不会因为您的安全性不足而遭受损失)。请记住,任何形式的成功社交工程和密码重用都会阻碍您的最佳尝试,因此强制实施强密码策略至关重要。

自动密码重置

您可以采取其他辅助措施,使统计上不值得尝试,例如自动密码重置,并将访问链接发送到用户帐户。这些类型的操作取决于产品的性质以及您要保护的内容。例如,由于受损帐户的严重性,银行网站会锁定连续错误尝试次数过多的帐户。

使用CAPTCHA

我可能规定的最简单的威慑力是在任何给定IP连续3次尝试失败之后要求强大的CAPTCHA(我推荐ReCAPTCHA),无论用户/电子邮件是否尝试过。同一IP后面的用户可能必须立即进入CAPTCHA,因为其他用户尝试失败,但这是为安全性付出的小代价。作为ReCAPTCHA面对的攻击者,我会放弃。

延迟尝试

一种不那么有冲击力的方法是通过在连续3次尝试失败后引入合成身份验证延迟来限制密码尝试次数。这通过限制N小时的尝试次数来降低暴力攻击的可行性,当与强制密码到期策略相结合时,将阻止暴力攻击。


在旁注中,请确保只存储用户密码的盐渍哈希值,每个密码使用不同的盐,并拒绝常用密码和字典词。

答案 2 :(得分:1)

无论您如何持久保存数据,您可能都希望创建ASP.Net MembershipProvider的子类,以便与所有不错的ASP.Net成员资格相结合。

the MSDN for information on SqlMembershipProvider为例。您可以使用任何ASP.Net成员资格提供程序作为基础,甚至可以通过继承基本抽象类来直接实现您自己的成员资格提供程序。

正如@Novikov在下面的评论中指出的那样,您只需使用MaxInvalidPasswordAttemptsPasswordAttemptWindow即可获得所需的功能。

这是一个示例类:

public class MyMagicCloudMembershipProvider : System.Web.Security.MembershipProvider 
{    
  public override bool ValidateUser(string username, string password)
  {
    return ToTheCloud.WithWindowsSeven(user, password);
  }
}

然后,您可以很好地使用您的web.config - 您只需提供您的会员提供商的类型,然后一切都使用它。然后,您可以使用所有默认的Webforms登录控件,ASP.Net将调用您的成员资格提供程序中的方法。

答案 3 :(得分:1)

根据你的限制,我只看到了T.J.没提。这是一种贫民窟的方式,可能行不通。如果它确实有效,它将无法正常工作。如果我的答案非常可怕,请不要将我投票给负面的声誉。这是我能用这些限制得出的唯一答案,我认为这是你得到的最佳答案(除了改变你的限制或遵循T.J的建议)。

您可以使用JavaScript(这不是一个好的解决方案)。您可以使用onload()和onunload()事件来提交页面(TO ITSELF)并传播状态。这个概念极其迟钝,因为用户只需要清除他们的浏览器就可以打败它。

正如大家已经提到的,这些数据需要存储在某个地方。存储此信息的最佳位置在您的服务器上。您可以将这些信息存储在cookie中(这不是一个好主意),您可以将这些信息存储在提交给您服务器的表单变量中(更好的主意),您可以将这些信息存储在提交给您自己的表单变量中(我的可怕想法)或者你可以将它们存放在其他地方(TJ Crowder的好主意)。你想把它们存放在哪里?

答案 4 :(得分:1)

我同意上面的许多帖子及其建议。我在所有公司网站上实现此功能,并使用数据库来执行此操作。

请将此作为您网站上数据库的一项功能实现,然后您可以继续使用此代码在您现在构建的每个网站中,而无需使用您的现有代码,而不是我建议的黑客。

那说要用你给定的限制来解决你的问题,我建议如下。

将对象存储在应用程序/ Web缓存中。这可以是一个列表,一个示例可能是失败的登录尝试列表。

伪代码...

列表

公共类LoginAttempt {     公共字符串IP {get; set;}     public DateTime AttemptTime {get; set;} }

在global.asax应用程序启动事件中初始化此obeject列表。

现在,当您尝试失败时,请在此对象中添加一个条目。

现在你可以使用一些LINQ在有人试图登录时进行一些检查。

if(CachedLoginAttempts.Where(x => x.IP&& x.AttemptTime> DateTime.Now.AddMinutes( - 你想要锁定多长时间))。Count()>失败了多少您想要允许的登录尝试) {    让...进 }

如果您以前没有使用它,请查看此页面以了解如何在.NET中使用缓存。

http://www.aspnettutorials.com/tutorials/network/web-caching-csharp.aspx

答案 5 :(得分:0)

我唯一能想到的就是使用文件。如果你不能修改你的数据库模型,并且不能依赖任何其他外部方式来保存信息,那就是你要做的。

当然,您不能简单地在服务器中使用简单的txt并将其调用完成 - 在处理多用户场景中如何访问该文件时会遇到很多问题,或者如果您遇到了什么当您要写入文件时,就会出现硬件问题。而且,如果文件损坏会发生什么?关于encription,是一个简单的txt安全,足以容纳所有用户的名字?

因此,您必须编写一个管理此文件的组件。可能是一个懒惰加载文件并在必要时将其重写到磁盘的单例。 可能将请购单排入队列,但如果您拥有大型用户社区(> 1000),那么您将遇到性能瓶颈。所以也许你每次发生变化时都不编写文件,或者你可能会编写许多文件以避免同时发生。但是你需要一个启发式方法来确定要写的文件和...

看看我要去哪里?您最好的选择是自己编写一个迷你DBMS,并承担使用这种弱方法的风险。但是,我一直在那里做了类似的事情,但它与我的应用程序的安全性甚至没有密切关系,我有一个非常好的限制:文件中只有一条记录。