如何使用ASP.NET的表单认证,在记住密码和安全性之间找到平衡点

最近项目里遇到一点表单验证的问题,发现网上很多文章都说的很浅,很多是抄来抄去,特此记录下来

主要就是即如何给非持久性认证令牌cookie有效期,在记住密码和安全性之间找到平衡点

一来自己加深印象和备查,另外也希望能给一些困扰的人一点帮助

预先说明一点:下面的内容都是针对ASP.NET的,其他的具体原理和代码类似

首先说说我们常用的身份验证机制,我想大家都明白,主要是session机制和cookie机制

session机制是由服务器来负责维护每个会话的状态维护,session主要分存储在内存里(当应用崩溃或其他内存问题就丢失,一般只适用小项目)和数据库里。这里就不具体展开了。

但越来越多的应用还是采取cookie机制,一是减轻服务器的负担,二是很多应用有需要记住密码免登录的功能,这都是cookie能方便快速实现的。

而ASP.NET本身提供了Form表单认证和Login组件就能方便地实现这点

简单的说就是登录成功了,服务器会response输出一个加密过的cookie令牌数据,这个令牌数据被浏览器自动存储,每次发送新的浏览请求都会自动带上这个cookie

服务器在得到request的请求时会自动判断这个cookie是否有效,有效就能正确得到membership的user。

这里有个问题,就是登录成功了服务器到底给你的令牌cookie有效期到底是多久?

在ASP.NET提供的FormAuthentication机制里

如果是希望本地记住密码的方式登录,那么给你的cookie就是持久性cookie,也就是这个cookie被存储在浏览器的本地缓存文件里,下次打开浏览器就不用重新登录。而有效期是由WEB.CONFIG里设置决定的。

如果是当前登录不希望记住密码,那么给你的cookie就是非持久性性的,也就是浏览器关闭后这个cookie自动清除,下次就需要重新登录

下面是WEB.CONFIG里此项的重要配置

<authentication mode="Forms" >
     <forms name="yourauthenticationcookiename" protection="All" timeout="20" slidingExpiration="true" cookieless="UseCookies" />
</authentication>

  

 name="yourauthenticationcookiename" 这个name就是唯一标记这个认证和cookie的

 protection="all" 很重要,此项为all那么服务器将会校验每次cookie是否被伪造等,加密发送等

 timeout="4320" 如果记住密码,那么持久性cookie的有效期,单位是分钟。以4320为例是30天,意味着这次登录后,3天内你第2次打开浏览器都不用重新登录,如果第4天才第2次打开就需重新登录。 显然这个时间设置的太长会安全性很差,太短可能会导致即便记住密码了也常要登录。我的建议是3天,也就是4320(理由见后)

 slidingExpiration="true" 此选项表示是否自动续有效期,这完全要看自己应用的需求,如果对安全性要求高,这个选项最好是false,这样每当timeout后就强制需要重新登录。如果为了个人记住密码免登录使用 方便,那就选true,这样假设有效期是3天,你如果周一登录,周二免登录用了一次,周三免登录又用了一次,这时过了有效期的一半了,系统自动将你有效期算到周三后的3天。这样一直循环 往复。所以设置3天,会方便哪些周五还使用的人,下周一还是可以免登录的。

 cookieless="UseCookies" 本来这个属性是默认使用设备的设置,但现在各种手机和平板,它们有些没声明自己是否支持cookie导致认证失效,所以强制让服务器声明使用cookie cookieless="UseCookies" /

 

有了上面的设置,大家很清楚,一般我们会设置一个几天的有效期,如果是记住密码的,那么由timeout来控制何时这个令牌失效,如果是不记住密码登录方式则是一个临时性的会话令牌,一旦浏览器关闭就销毁。

但现在出现新的问题,细心的人会注意到临时性的会话令牌和浏览器是否关闭有关,我们就是因为这点发现新的问题

一次是会议室开会,点不保存密码登录(也就是临时性会话),但后来没有关闭浏览器,直接关机了。第2次开机时,打开浏览器,浏览器提示是否恢复上次的未正常关闭的网页,点是,结果还是在登录状态。

另外一次是使用客户的电脑,点不保存密码登录(也就是临时性会话),结果后来有事急着走,也是浏览器没有关闭,直接电脑休眠盖上,若干天后客户重新唤醒电脑,还是在登录状态。

 

这里就说明这种临时性的会话令牌是存储在浏览器的内存里(浏览器恢复上次异常也是恢复了它的内存数据),这显然有巨大的安全隐患,毕竟忘记关浏览器概率还是不小。 那我们就需要不记住密码时的临时性登录的会话有效期不是以关闭浏览器为准。这点其他服务器端使用cookie做认证的也都一样有这个问题,要么是持久性cookie,要么是非持久性cookie,非持久性的如果浏览器一直没关也就一直保持认证。

 

但遗憾的是表单认证架构里默认没有考虑这点(他们或许认为你一次性登录,肯定以你关闭浏览器为准,你没关闭说明你还在工作) 也就是说webconfig没有地方说你可以设置临时性会话的有效期。(其实持久性认证令牌cookie所谓的过期也是指你浏览器关闭以后重新打开计。就是说假设你记住密码登录的,服务器设置过期时间是1小时,如果你1点登录没有关闭浏览器,即便到过了2小时3小时,你之前的认证也依然有效。当然毕竟一般只有在自己私人电脑才选择记住密码,所以问题也不算严重)

 

这就需要我们自己在处理Request请求入口的处理代码里加上判断

具体思路是这样的,我们需要知道当前的用户令牌到底是持久性还是非持久性的,并得到这个令牌最早是什么时候派发的 尤其是针对非持久性令牌cookie的处理 下面是我的一段处理代码,放在我的网页处理根类的load事件里(这个视自己项目和代码而定) 

if (HttpContext.Current.Request.IsAuthenticated == true) //验证过的用户才进行处理
{
  FormsIdentity Id = (FormsIdentity)HttpContext.Current.User.Identity;
  FormsAuthenticationTicket Ticket = Id.Ticket; //取得身份验证票
  //如果是临时性的验证凭证,则过10分钟自动过期
  if (!Ticket.IsPersistent)
  {
    //如果取得临时凭证时间超过1小时,即立刻将临时凭证取消,重新登录
    if (Ticket.IssueDate.AddHours(1) < DateTime.Now)
    {
      FormsAuthentication.SignOut();
      Session.Abandon();
      Response.Redirect(”/login.aspx");
    }
  }
     else
     {
       //如果是持久性的,判断是否有效期到了,这样即便没关闭浏览器也强行处理
    if (Ticket.Expiration< DateTime.Now)
    {
      FormsAuthentication.SignOut();
      Session.Abandon();
      Response.Redirect(”/login.aspx");
    }
     }
}

  

 

这样处理之后相当于我们给你非持久性的认证令牌cookie一个有效期,有效期是1小时

到期后,如果点击任何一个网页请求,都自动退出当前的登陆并返回登陆页

 

这样处理完以后,我们算找到了一个平衡点

在自己的私人电脑上还是推荐使用记住密码,这样免得经常要登录,直到连续超过timeout的时间么有使用才需要重新登录

而临时性登录则不用担心自己离开后,由于电脑或浏览器未关导致他人依然可以使用。例子中我设置为1小时主要是考虑客户经常在会议室开会使用可能一般要几十分钟。其实建议时间更短一些

 

 

一直没在博客园写什么,发现排版好不方便啊,不知经常看到的一些帖子是用什么发的?

 文章和随笔有啥区别?

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。