日期:2014-02-10  浏览次数:20429 次


原创 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=3FF83247C29EB5D14D61F389D453EEE0586B94E27609C321B017BE7B88D1A94D249996428A7A18F5C2D69F3C4DD2B88C00172CAFB0B4B4ED8784DB62D1D61BCC0C786B4EA7868FC6
    看来这就是加密以后的Cookie了。下面要换一台电脑,直接将这个值设置为Cookie,看看是否需要Forms验证。
    在Login.aspx页面中加上这样一句话:
     <script language=javascript>
 document.cookie="MyLab=3FF83247C29EB5D14D61F389D453EEE0586B94E27609C321B017BE7B88D1A94D249996428A7A18F5C2D69F3C4DD2B88C00172CAFB0B4B4ED8784DB62D1D61BCC0C786B4EA7868FC6";
 </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) FormsAuthenticati