软件开发
开发分享
软件下载

.NET 4.0以下CookieContainer域名处理Bug及解决方案

时间:2020-09-10 来源:juhe99 点击量:

.NET 4.0以下CookieContainer域名处理Bug及解决方案

重要提示:.NET 4.0以下的CookieContainer存在一个bug,即主域和子域cookie互访有问题。Microsoft决定不在.NET 2.0/3.0/3.5中修复此问题。

问题背景

CookieContainer在处理域名时存在问题,这会影响客户端浏览器或处理器对cookie的访问控制:

  • 不同域名的Web不能访问其他域名的cookie

  • 子域名可以访问该子域名及其所有父域名的cookie

  • 父域名或域名本身不能访问其任何子域名的cookie

问题分析

CookieContainer内部结构:

CookieContainer cc has m_domainTable field
Hashtable m_domainTable
  Hashtable Key: string domain
  Hashtable Value: PathList pathList

PathList pathList has m_list field
  SortedList m_list
    Key: string path
    Value: CookieCollection colCookies

CookieContainer有三个关键方法:Add、GetCookies和SetCookies,但它们在处理域名时存在以下问题:

Add方法问题

  1. Add(Cookie) vs Add(Uri, Cookie)重载:

    • Add(Cookie):直接使用cookie的domain属性作为hashtable键存储

    • Add(Uri, Cookie):使用rfc2109标准,所有域名都以点开头存储

  2. 问题本质:Add(Cookie)将.sub.domain.com和sub.domain.com存储在不同组中,但从逻辑上讲,这两个cookie都应该对http://sub.domain.com可见

GetCookies方法问题

  1. 问题#1:无法检索以点开头的当前子域名cookie和不以点开头的父域名cookie

  2. 问题#2:无法检索当前子域名cookie,因为子域名在开头添加了点

解决方案

Bug修复函数

private void BugFix_CookieDomain(CookieContainer cookieContainer)
{
    Hashtable table = (Hashtable)_ContainerType.InvokeMember("m_domainTable",
        System.Reflection.BindingFlags.NonPublic |
        System.Reflection.BindingFlags.GetField |
        System.Reflection.BindingFlags.Instance,
        null,
        cookieContainer,
        new object[] { });
    ArrayList keys = new ArrayList(table.Keys);
    foreach (string keyObj in keys)
    {
        string key = (keyObj as string);
        if (key[0] == '.')
        {
            string newKey = key.Remove(0, 1);
            table[newKey] = table[keyObj];
        }
    }
}

使用建议

文章重点总结:

  1. 避免使用Add(Cookie):始终使用Add(Uri, Cookie)

  2. 及时调用修复函数:每次添加cookie后或使用GetCookies前调用BugFix_CookieDomain函数

  3. 系统使用前检查:在系统使用CookieContainer容器前调用修复函数

技术说明:此修复方案假设始终使用Add(Uri, Cookie)方法并且已创建点域名键。更好的编码方式是修改此代码以确保点域名键始终镜像到非点域名键,反之亦然,这样就可以使用Add(Cookie)方法。