",IsolateApps"能区分任何两个Web Application吗

来源:互联网 发布:tightvnc软件怎么使用 编辑:程序博客网 时间:2024/05/16 01:31

    在《ASP.NET虚拟主机中Forms Authentication的安全性》中,我用同一台电脑的一个站点上创建的验证Cookie通过了另一个站点的表单验证,然后我得出一个结论:MachineKey的确只与Machine有关,而与WebApplication无关。在web.config文件<configuration>-<system.web>下的<machineKey>中可能的配置如下:
<machineKey validationKey="AutoGenerate|value[,IsolateApps]"
            decryptionKey="AutoGenerate|value[,IsolateApps]"
            validation="SHA1|MD5|3DES"/>
    MSDN对IsolateApps的解释如下:
If you add the IsolateApps modifier to the validationKey value, ASP.NET generates a unique encrypted key for each application using each application's application ID.
    这就是说,加上",IsolateApps"以后每个Web应用程序所用的MachineKey就都不一样了,一个程序中生成的验证Cookie在另一个应用程序中就通不过了。那么我实验的结果是因为没有设置",IsolateApps"吗?我修改了两个Web站点的Web.config文件,分别加上了
<machineKey validationKey="AutoGenerate,IsolateApps"
            decryptionKey="AutoGenerate,IsolateApps"
            validation="SHA1" />
    结果再次出乎我的预料!其中一个站点生成的验证Cookie还是通过了另一个站点的验证。重新启动系统、更换用户名之类我都是过了,但结果没有改变。这与MSDN上说的可不一样。答案也只有用Reflector来寻找了。
    找到了分析<machineKey>这一段的代码,位于System.Web.Configuration.MachineKey.MachineKeyConfig..ctor(Object, Object, XmlNode)。代码比较长,不过还是贴出来比较方便。

  1internal MachineKeyConfig(object parentObject, object contextObject, XmlNode node)
  2{
  3      MachineKey.MachineKeyConfig config1 = (MachineKey.MachineKeyConfig) parentObject;
  4      HttpConfigurationContext context1 = contextObject as HttpConfigurationContext;
  5      if (HandlerBase.IsPathAtAppLevel(context1.VirtualPath) == PathLevel.BelowApp)
  6      {
  7            throw new ConfigurationException(HttpRuntime.FormatResourceString("No_MachineKey_Config_In_subdir"), node);
  8      }

  9      if (config1 != null)
10      {
11            this._ValidationKey = config1.ValidationKey;
12            this._DecryptionKey = config1.DecryptionKey;
13            this._ValidationMode = config1.ValidationMode;
14            this._AutogenKey = config1.AutogenKey;
15      }

16      XmlNode node1 = node.Attributes.RemoveNamedItem("validationKey");
17      XmlNode node2 = node.Attributes.RemoveNamedItem("decryptionKey");
18      int num1 = 0;
19      string[] textArray2 = new string[3] { "SHA1", "MD5", "3DES" } ;
20      string[] textArray1 = textArray2;
21      XmlNode node3 = HandlerBase.GetAndRemoveEnumAttribute(node, "validation", textArray1, ref num1);
22      if (node3 != null)
23      {
24            this._ValidationMode = (MachineKeyValidationMode) num1;
25      }

26      HandlerBase.CheckForUnrecognizedAttributes(node);
27      HandlerBase.CheckForChildNodes(node);
28      if ((node1 != null) && (node1.Value != null))
29      {
30            string text1 = node1.Value;
31            bool flag1 = text1.EndsWith(",IsolateApps");
32            if (flag1)
33            {
34                  text1 = text1.Substring(0, text1.Length - ",IsolateApps".Length);
35            }

36            if (text1 == "AutoGenerate")
37            {
38                  this._ValidationKey = new byte[0x40];
39                  Buffer.BlockCopy(HttpRuntime.s_autogenKeys, 0, this._ValidationKey, 0, 0x40);
40            }

41            else
42            {
43                  if ((text1.Length > 0x80) || (text1.Length < 40))
44                  {
45                        throw new ConfigurationException(HttpRuntime.FormatResourceString("Unable_to_get_cookie_authentication_validation_key", text1.Length.ToString()), node1);
46                  }

47                  this._ValidationKey = MachineKey.HexStringToByteArray(text1);
48                  if (this._ValidationKey == null)
49                  {
50                        throw new ConfigurationException(HttpRuntime.FormatResourceString("Invalid_validation_key"), node1);
51                  }

52            }

53            if (flag1)
54            {
55                  int num2 =
SymbolHashCodeProvider.Default.GetHashCode(HttpContext.Current.Request.ApplicationPath);
56                  this._ValidationKey[0] = (byte) (num2 & 0xff
);
57                  this._ValidationKey[1] = (byte) ((num2 & 65280) >> 8
);
58                  this._ValidationKey[2] = (byte) ((num2 & 16711680) >> 0x10
);
59                  this._ValidationKey[3] = (byte) ((num2 & 4278190080) >> 0x18
);
60            }

61      }

62      if (node2 != null)
63      {
64            string text2 = node2.Value;
65            bool flag2 = text2.EndsWith(",IsolateApps");
66            if (flag2)
67            {
68                  text2 = text2.Substring(0, text2.Length - ",IsolateApps".Length);
69            }

70            if (text2 == "AutoGenerate")
71            {
72                  this._DecryptionKey = new byte[0x18];
73                  Buffer.BlockCopy(HttpRuntime.s_autogenKeys, 0x40, this._DecryptionKey, 0, 0x18);
74                  this._AutogenKey = true;
75            }

76            else
77            {
78                  this._AutogenKey = false;
79                  if (text2.Length == 0x30)
80                  {
81                        TripleDESCryptoServiceProvider provider1 = null;
82                        try
83                        {
84                              provider1 = new TripleDESCryptoServiceProvider();
85                        }

86                        catch (Exception)
87                        {
88                        }

89                        if (provider1 == null)
90                        {
91                              throw new ConfigurationException(HttpRuntime.FormatResourceString("cannot_use_Triple_DES"), node2);
92                        }

93                  }

94                  if ((text2.Length != 0x30) && (text2.Length != 0x10))
95                  {
96                        throw new ConfigurationException(HttpRuntime.FormatResourceString("Unable_to_get_cookie_authentication_decryption_key", text2.Length.ToString()), node2);
97                  }

98                  this._DecryptionKey = MachineKey.HexStringToByteArray(text2);
99                  if (this._DecryptionKey == null)
100                  {
101                        throw new ConfigurationException(HttpRuntime.FormatResourceString("Invalid_decryption_key"), node2);
102                  }

103            }

104            if (flag2)
105            {
106                  int num3 = SymbolHashCodeProvider.Default.GetHashCode(HttpContext.Current.Request.ApplicationPath);
107                  this._DecryptionKey[0] = (byte) (num3 & 0xff);
108                  this._DecryptionKey[1] = (byte) ((num3 & 65280) >> 8);
109                  this._DecryptionKey[2] = (byte) ((num3 & 16711680) >> 0x10);
110                  this._DecryptionKey[3] = (byte) ((num3 & 4278190080) >> 0x18);
111            }

112      }

113}

114

    这段程序从配置文件中分析了validationKey和decryptionKey,他们两个的处理过程很相似。第16行node1是validationKey,第28行开始对其进行分析。第31行bool flag1 = text1.EndsWith(",IsolateApps");用flag1表示是否有",IsolateApps"。下面从36至52行都没用到flag1。53-60是关键。看到这里就明白了,MSDN中所说的“application's application ID”其实就是HttpContext.Current.Request.ApplicationPath,不同的ApplicationPath所生成的validationKey和decryptionKey就不一样。
    因为我上面做实验是用的两个不同的WebSite,当然也是不同的WebApplication,但由于两个WebApplication的ApplicationPath都是"/",所以它们的validationKey和decryptionKey是相同的!要是在相同的WebSite建立不同的虚拟目录并配置成应用程序,所生成的Cookie就不通用了。我也做了实验,证实了这一点,步骤就不用说了。
    这也验证了我在《ASP.NET虚拟主机中Forms Authentication的安全性》中得到的结论,在虚拟主机环境中使用表单验证时很容易被同一台电脑上的其它WebApplication所欺骗。虽然validationKey和decryptionKey还可以在web.config中自定义,可是有多少虚拟主机提供商对不同的WebApplication用了不同的用户运行,并且对每个站点目录配置了恰当的NTFS权限呢?

------------------------------------------------------
测试环境:Windows 2003, .NET Framework 1.1 sp1(--2005-7-27补充)