You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何绕过IE Cookie使C#代码适配Microsoft Edge运行?

问题:绕过IE Cookie,让依赖wininet.dll的C#代码适配Edge运行

我有一段C#代码,用于连接预设API列表并获取特定数据,但代码严重依赖wininet.dll的InternetGetCookieEx函数。现在IE已停止服务,代码无法正常运行,想知道能不能绕过IE Cookie,让代码适配Microsoft Edge。

我的项目里有controllers文件夹,包含以下文件:

1. StaticStrings.cs

用于定义API地址(代码略)

2. WebNav.cs(原代码)

原代码通过调用wininet.dll的InternetGetCookieEx获取Cookie:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

internal sealed class NativeMethods
{
    #region enums

    public enum ErrorFlags
    {
        ERROR_INSUFFICIENT_BUFFER = 122,
        ERROR_INVALID_PARAMETER = 87,
        ERROR_NO_MORE_ITEMS = 259
    }

    public enum InternetFlags
    {
        INTERNET_COOKIE_HTTPONLY = 8192, //Requires IE 8 or higher   
        INTERNET_COOKIE_THIRD_PARTY = 131072,
        INTERNET_FLAG_RESTRICTED_ZONE = 16
    }

    #endregion

    #region DLL Imports

    [SuppressUnmanagedCodeSecurity, SecurityCritical, DllImport("wininet.dll", EntryPoint = "InternetGetCookieExW", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
    internal static extern bool InternetGetCookieEx([In] string Url, [In] string cookieName, [Out] StringBuilder cookieData, [In, Out] ref uint pchCookieData, uint flags, IntPtr reserved);

    #endregion
}

namespace WeeklySchedule.Contollers
{
    public class FullWebBrowserCookie : WebBrowser
    {

        [SecurityCritical]
        public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
        {
            uint pchCookieData = 0;
            string url = UriToString(uri);
            uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;

            //Gets the size of the string builder   
            if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
            {
                pchCookieData++;
                StringBuilder cookieData = new StringBuilder((int)pchCookieData);

                //Read the cookie   
                if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
                {
                    DemandWebPermission(uri);
                    return cookieData.ToString();
                }
            }

            int lastErrorCode = Marshal.GetLastWin32Error();

            if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
            {
                throw new Win32Exception(lastErrorCode);
            }

            return null;
        }

        private static void DemandWebPermission(Uri uri)
        {
            string uriString = UriToString(uri);

            if (uri.IsFile)
            {
                string localPath = uri.LocalPath;
                new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
            }
            else
            {
                new WebPermission(NetworkAccess.Connect, uriString).Demand();
            }
        }

        private static string UriToString(Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
            return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
        }
    }
}

3. WebAPI.cs

通过获取的Cookie调用API,获取预订时长、订单状态等数据:

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using WeeklyScheduleModels;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks;

namespace WeeklySchedule.Contollers
{
    class WebAPI
    {
        public string GetNorderTimeExpensebyNo(string norderNo)
        {
            return "OK";
        }

        public string GetNorderDbIDfromNo(string norderNo)
        {
            return "";
        }

        public double GetBookedHours(string subOrderNo)
        {
            var cookies = FullWebBrowserCookie.GetCookieInternal(new Uri(StaticStrings.UrlNCert), false);

            WebClient wc = new WebClient();
            wc.Encoding = System.Text.Encoding.UTF8;
            wc.Headers.Add("Cookie:" + cookies);
            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            string uri = "";

            double totalHours = 0.0;
            uri = StaticStrings.NOrderTimeExpenseAPI + subOrderNo;
            var response = wc.DownloadString(uri);
            NCertTimeExpenseMain ntem = JsonConvert.DeserializeObject<NCertTimeExpenseMain>(response);
            foreach (OracleHour oh in ntem.oracleHours)
            {
                totalHours += oh.hours;
            }

            return totalHours;
        }

        //获取项目在Ncert中的状态
        public string GetOrderStatus(string subOrderNo)
        {
            var cookies = FullWebBrowserCookie.GetCookieInternal(new Uri(StaticStrings.UrlNCert), false);
            WebClient wc = new WebClient();
            wc.Encoding = System.Text.Encoding.UTF8;
            wc.Headers.Add("Cookie:" + cookies);
            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            string uri = "";

            uri = StaticStrings.OrderStatusAPI + subOrderNo+'?';
            var response = wc.DownloadString(uri);
            
            RootObject status = JsonConvert.DeserializeObject<RootObject>(response);
            
            string currentstatusofproject = status.statusDescription;
            return currentstatusofproject;
        }
    }
}

我尝试把WebNav.cs里的GetCookieInternal方法改成用CookieContainer获取Cookie,但还是不能正常工作:

using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WeeklySchedule.Contollers
{
    public class FullWebBrowserCookie : WebBrowser
    {
        public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
        {
            var cookieContainer = new CookieContainer();
            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.CookieContainer = cookieContainer;
            request.AllowAutoRedirect = false;

            using (var response = (HttpWebResponse)request.GetResponse())
            {
                cookieContainer.Add(response.Cookies);
            }

            var cookies = cookieContainer.GetCookies(uri);
            if (cookies.Count == 0 && throwIfNoCookie)
            {
                throw new Exception("No Cookies found for the given URI");
            }

            return string.Join(";", cookies.OfType<Cookie>().Select(c => c.Name + "=" + c.Value));
      }
}

解决方案

核心问题分析

你之前用CookieContainer的尝试无效,是因为这种方式是发起全新的HTTP请求获取Cookie,而不是读取Edge浏览器已保存的用户会话Cookie。Edge现在使用Chromium内核,不再共享IE的Cookie存储,wininet.dll只能读取IE/旧Edge的Cookie池,所以必须换用Chromium内核对应的Cookie读取方式。

可行方案:读取Edge Chromium的Cookie数据库

Edge Chromium把Cookie存储在SQLite数据库里,路径一般是:

  • Windows: C:\Users\<你的用户名>\AppData\Local\Microsoft\Edge\User Data\Default\Network\Cookies
  • macOS: ~/Library/Application Support/Microsoft Edge/Default/Network/Cookies

要读取这个数据库,需要:

  1. 引用SQLite库(比如Microsoft.Data.Sqlite)
  2. 处理Cookie数据库的加密(Windows下使用DPAPI加密)

代码实现示例

步骤1:安装NuGet包

安装Microsoft.Data.Sqlite和System.Security.Cryptography.ProtectedData(用于解密Windows下的Cookie)

步骤2:替换FullWebBrowserCookie类

using System;
using System.Collections.Generic;
using Microsoft.Data.Sqlite;
using System.Security.Cryptography;
using System.Text;
using System.IO;

namespace WeeklySchedule.Contollers
{
    public static class EdgeCookieHelper
    {
        // 获取Edge Cookie数据库路径
        private static string GetEdgeCookieDbPath()
        {
            string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
            return Path.Combine(userProfile, @"AppData\Local\Microsoft\Edge\User Data\Default\Network\Cookies");
        }

        // 解密Windows下的Cookie值(DPAPI加密)
        private static string DecryptCookieValue(byte[] encryptedValue)
        {
            try
            {
                byte[] decryptedData = ProtectedData.Unprotect(encryptedValue, null, DataProtectionScope.CurrentUser);
                return Encoding.UTF8.GetString(decryptedData);
            }
            catch
            {
                return null;
            }
        }

        // 根据URL获取Cookie字符串
        public static string GetEdgeCookies(Uri uri, bool throwIfNoCookie)
        {
            string dbPath = GetEdgeCookieDbPath();
            if (!File.Exists(dbPath))
            {
                if (throwIfNoCookie)
                    throw new FileNotFoundException("Edge Cookie数据库不存在");
                return null;
            }

            // 复制数据库文件(因为Edge运行时会锁定原文件)
            string tempDbPath = Path.Combine(Path.GetTempPath(), $"EdgeCookies_{Guid.NewGuid()}.db");
            File.Copy(dbPath, tempDbPath, true);

            var cookiePairs = new List<string>();
            using (var connection = new SqliteConnection($"Data Source={tempDbPath}"))
            {
                connection.Open();
                // 查询匹配当前域名的有效Cookie
                string query = @"
                    SELECT name, value 
                    FROM cookies 
                    WHERE host_key LIKE @hostKey 
                    AND expires_utc > @currentTime 
                    AND is_secure = 0"; // 根据需要调整is_secure(1是HTTPS专属)

                using (var command = new SqliteCommand(query, connection))
                {
                    // 匹配域名,比如要匹配*.example.com就用%example.com
                    command.Parameters.AddWithValue("@hostKey", "%" + uri.Host);
                    command.Parameters.AddWithValue("@currentTime", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());

                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            string name = reader.GetString(0);
                            byte[] encryptedValue = reader.GetValue(1) as byte[];
                            string value = DecryptCookieValue(encryptedValue);
                            if (!string.IsNullOrEmpty(value))
                            {
                                cookiePairs.Add($"{name}={value}");
                            }
                        }
                    }
                }
                connection.Close();
            }

            // 删除临时文件
            File.Delete(tempDbPath);

            if (cookiePairs.Count == 0 && throwIfNoCookie)
                throw new Exception("未找到匹配的Edge Cookie");

            return string.Join(";", cookiePairs);
        }
    }
}

步骤3:修改WebAPI.cs中的调用

把原来的FullWebBrowserCookie.GetCookieInternal替换为EdgeCookieHelper.GetEdgeCookies:

// 替换这一行
var cookies = EdgeCookieHelper.GetEdgeCookies(new Uri(StaticStrings.UrlNCert), false);

其他注意事项

  • 权限问题:程序需要读取用户AppData目录的权限,运行时不要用管理员权限(DPAPI解密需要当前用户上下文)
  • Edge运行时锁定:复制数据库文件是必须的,因为Edge打开时会锁定原Cookie数据库
  • HTTPS Cookie:如果API用HTTPS,需要把查询语句里的is_secure = 0改成is_secure = 1
  • 跨平台适配:如果需要支持macOS,需要替换解密逻辑为Keychain读取

内容的提问来源于stack exchange,提问作者parna deljo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 13:15:24