如何绕过IE Cookie使C#代码适配Microsoft 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
要读取这个数据库,需要:
- 引用SQLite库(比如
Microsoft.Data.Sqlite) - 处理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

