ASP.NET Forms Authentication所生成Cookie的安全性

原创 2005年04月26日 19:40:00

原创 By Fancyf(Fancyray)

    我做这个实验是因为http://community.csdn.net/Expert/topic/3927/3927012.xml?temp=.3752405
    最初我想,.NET的验证应该是比较安全的吧,生成的Cookie也应该与这台电脑的独特的参数相关,

拿到另一台电脑上就应该无效了。那么是不是一个用户名对应一个Cookie值呢?是否能够通过伪造

Cookie值来骗过表单验证呢?做一番试验。
    Web.config修改如下:
    <authentication mode="Forms">
  <forms name="MyLab" loginUrl="/Login.aspx">
   <credentials passwordFormat="Clear">
    <user name="Fancyray" password="Fancyray"/>
   </credentials>
  </forms>
    </authentication>

    <authorization>
        <deny users="?" />
    </authorization>

    Login.aspx只有一个用户名输入框txtUsername、一个密码输入框txtPassword和一个提交按钮,

Click事件如下:
if (FormsAuthentication.Authenticate(this.txtUsername.Text, this.txtPassword.Text))
{
 FormsAuthentication.RedirectFromLoginPage(this.txtUsername.Text, true);
}
else
{
 Response.Write("Login denied");
}
    借助ieHttpHeaders(http://www.blunck.info/ )可以看到,通过验证后增加了一个类似这样的Cookie:
MyLab=3FF83247C29EB5D14D61F389D453EEE0586B94E27609C321B017

BE7B88D1A94D249996428A7A18F5C2D69F3C4DD2B88C00172CAFB0B4B4ED8784DB62D1D

61BCC0C786B4EA7868FC6
    看来这就是加密以后的Cookie了。下面要换一台电脑,直接将这个值设置为Cookie,

看看是否需要Forms验证。
    在Login.aspx页面中加上这样一句话:
     <script language=javascript>
 document.cookie="MyLab=3FF83247C29EB5D14D61F389D453EEE0586B94

E27609C321B017BE7B88D1A94D249996428A7A18F5C2D69F3C4DD2B88C

00172CAFB0B4B4ED8784DB62D1D61BCC0C786B4EA7868FC6";
 </script>
    这样只要一打开Login.aspx页面就会自动加入这个Cookie。
    另一台电脑:输入同一个WebApplication下的另外一个页面(应该会自动跳转到Login.aspx页面)http://10.0.0.7/upload.aspx ,这时成功跳转到了http://10.0.0.7/Login.aspx?ReturnUrl=%2fupload.aspx ,正常。这时Cookie的值应该已经生效了。那么我们再输入刚才那个页面的网址http://10.0.0.7/upload.aspx
    按照我的猜想,肯定还会跳到login.aspx页面的,因为那个cookie是在另一台电脑上生成的。实际呢,没有跳转!完整地显示出了upload.aspx的内容!而我们根本没有在这台电脑上登录,甚至我们连用户名都不知道!
    我回到10.0.0.7这台电脑在upload.aspx页面的Page_Load()第一行添了一句:Response.Write(User.Identity.Name);,在另一台电脑上刷新显示出来了的upload.aspx,结果也出现了Fancyray,正是我的用户名。
    这说明,Cookie的加密不依赖于登录的电脑。也就是说,一旦你的Cookie被别人获得,他就有可能获得你在这台服务器上的权限。
    那么Cookie的这个值是怎么来的呢?黑客是否可能不通过穷举就得到这个值呢?


    我们先来看看Cookie中到底存储了一些什么,以及怎样进行的加密。Reflactor(http://www.aisto.com/roeder/dotnet )上场!
public static void SetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath)
{
      FormsAuthentication.Initialize();
      HttpContext.Current.Response.Cookies.Add(FormsAuthentication.GetAuthCookie(userName, createPersistentCookie, strCookiePath) );
}

public static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath)
{
      FormsAuthentication.Initialize();
      if (userName == null)
      {
            userName = "";
      }
      if ((strCookiePath == null) || (strCookiePath.Length < 1))
      {
            strCookiePath = FormsAuthentication.FormsCookiePath;
      }
      FormsAuthenticationTicket ticket1 = new FormsAuthenticationTicket(1, userName, DateTime.Now, createPersistentCookie ? DateTime.Now.AddYears(50) : DateTime.Now.AddMinutes((double) FormsAuthentication._Timeout), createPersistentCookie, "", strCookiePath);
      string text1 = FormsAuthentication.Encrypt(ticket1);
      FormsAuthentication.Trace("ticket is " + text1);
      if ((text1 == null) || (text1.Length < 1))
      {
            throw new HttpException(HttpRuntime.FormatResourceString("Unable_to_encrypt_cookie_ticket"));
      }
      HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, text1);
      cookie1.Path = strCookiePath;
      cookie1.Secure = FormsAuthentication._RequireSSL;
      if (ticket1.IsPersistent)
      {
            cookie1.Expires = ticket1.Expiration;
      }
      return cookie1;
}
    Cookie中存储的值就是里面的text1,text1是由string text1 = FormsAuthentication.Encrypt(ticket1);生成的,所以text1里面的信息就是ticket1了。FormsAuthenticationTicket的构造函数原形为:
public FormsAuthenticationTicket(int version, string name, DateTime issueDate, DateTime expiration, bool isPersistent, string userData, string cookiePath)
    里面有用户名、生成ticket1的时间和过期时间。
    看到这里我不禁打了一个冷颤。ticket1实际上只用到了用户名一个关键信息,连密码都没有用!这样岂不是任何一个用户的ticket1都可以轻易的制造出来吗?只要通过FormsAuthentication.Encrypt(ticket1)就得到了Cookie的值,来伪装成任何一个用户?太可怕了。现在只能寄希望于Encrypt这个函数了。看看它的实现:
public static string Encrypt(FormsAuthenticationTicket ticket)
{
      if (ticket == null)
      {
            throw new ArgumentNullException("ticket");
      }
      FormsAuthentication.Initialize();
      byte[] buffer1 = FormsAuthentication.MakeTicketIntoBinaryBlob(ticket);
      if (buffer1 == null)
      {
            return null;
      }
      if (FormsAuthentication._Protection == FormsProtectionEnum.None)
      {
            return MachineKey.ByteArrayToHexString(buffer1, 0);
      }
      if ((FormsAuthentication._Protection == FormsProtectionEnum.All) || (FormsAuthentication._Protection == FormsProtectionEnum.Validation))
      {
            byte[] buffer2 = MachineKey.HashData(buffer1, null, 0, buffer1.Length);
            if (buffer2 == null)
            {
                  return null;
            }
            FormsAuthentication.Trace("Encrypt: MAC length is: " + buffer2.Length);
            byte[] buffer3 = new byte[buffer2.Length + buffer1.Length];
            Buffer.BlockCopy(buffer1, 0, buffer3, 0, buffer1.Length);
            Buffer.BlockCopy(buffer2, 0, buffer3, buffer1.Length, buffer2.Length);
            if (FormsAuthentication._Protection == FormsProtectionEnum.Validation)
            {
                  return MachineKey.ByteArrayToHexString(buffer3, 0);
            }
            buffer1 = buffer3;
      }
      buffer1 = MachineKey .EncryptOrDecryptData(true, buffer1, null, 0, buffer1.Length);
      return MachineKey. ByteArrayToHexString(buffer1, buffer1.Length);
}
 
    看到了MachineKey这个词,终于松了一口气。看来加解密过程是与服务器的参数有关系。也就是说,服务器上有自己的密钥,只有用这个密钥才能进行Cookie的加解密。如果不知道这个密钥,别人是无法伪造Cookie的。

    看来Cookie还是安全的,在你的电脑没有被入侵的前提下。与其他任何信息一样,所需注意的仅仅是网络传输中的安全性了。
    Cookie的这个值和SessionID一样,都是一旦被猜中就可能引发安全问题。但又与SessionID有区别,因为SessionID总是短暂的,而Cookie的值却有可能是永远有效的。Cookie值的长度也让我们稍稍放了一点心。

    还有一个问题不容忽视。虽然Cookie的值的生成与具体的时间有关,也就是我注销后再次登陆所生成的Cookie是不一样的,但是一个合法的Cookie值是永久有效的,不受是否改变密码及时间的影响。也就是说,我上一次生成的Cookie在我注销以后拿到另一台电脑上仍然可以用,只要服务器的MachineKey不变。的确是个安全隐患。我们也只能说:“Cookie的值很长,要穷举到一个有效的Cookie在有生之年是办不到的”来找一些安慰。密码可以通过频繁的更改来进一步减小穷举到的可能性,但合法的Cookie却无法更改。密码是唯一的,但合法的Cookie值却不是唯一的。这一切总让人觉得不太放心。
    也许担心是多余的,因为电子签名、证书都是建立在“穷举要付出很大代价”的基础上的,要是考虑“碰巧被穷举到”的话,安全就不复存在了。相信在一般的安全领域,Forms生成的Cookie的安全级别还是足够的。
    放心地去用吧!(

ASP.NET Forms Authentication所生成Cookie的安全性

asp.net forms authentication所生成cookie的安全性 我做这个实验是因为http://community.csdn.net/expert/topic/3927/3927...

Asp.Net的Forms验证,解决Cookie和Seesion失效时间

  网站开发中用户验证一般采用Asp.Net的Forms验证,验证票据存储到Cookie的方式。     Session方式是将验证信息存储在内存中,如果你使用的虚拟主机给你分配很小的内存,实际上都...
  • logo616
  • logo616
  • 2011年05月13日 11:07
  • 1182

[.NET 基于角色安全性验证] 之三:ASP.NET Forms 身份验证

[ 2006-08-08 11:11:56 | 作者: yuhen ] 字号: 大 | 中 | 小 在开发过程中,我们需要做的事情包括: 1. 在 web.config 中设...

(待翻译)Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication

IIS and ASP.NET Processing Note   The information in this section applies to Internet Information...

ASP.NET authentication and authorization

关于Authentication和Authorization的入门级介绍。 Introduction This article will discuss how to implement ASP.NE...

ASP.NET Authentication Provider

http://ask.people.com.cn/ask/question.php?tid=1009&id=426506 ASP.NET 提供了一些新型的Authentication 和 Aut...

ASP.NET Identity Authentication

ASP.NET 认证与授权机制从基本的Form认证到后来的Membership认证,为ASP.NET应用构建了一个关于认证与授权的解决方案,开发者可以方便快捷地使用这个框架去解决应用认证与授权的问题....

Asp.net MVC Form authentication 示例代码

[HttpPost] public ActionResult LogOn(User model, string returnUrl) { if ...

(待翻译)Authentication Filters in ASP.NET Web API 2

An authentication filter is a component that authenticates an HTTP request. Web API 2 and MVC 5 both...

asp.net Forms身份验证详解

在做网站的时候,都会用到用户登录的功能。对于一些敏感的资源,我们只希望被授权的用户才能够访问,这让然需要用户的身份验证。对于初学者,通常将用户登录信息存放在Session中,笔者在刚接触到asp.ne...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ASP.NET Forms Authentication所生成Cookie的安全性
举报原因:
原因补充:

(最多只允许输入30个字)