【发布时间】:2020-02-14 16:48:09
【问题描述】:
我正在尝试从我的 Chrome 浏览器获取会话。我可以在开发者工具中看到 2 个 cookie 文件。但这对于用户从浏览器获取 cookie 值是不方便的,我想用代码来做。所以我使用此代码获取 Chrome 默认配置文件 cookie sqlite DB:
string local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string path = @"Google\Chrome\User Data\Default\Cookies";
path = Path.Combine(local, path);
接下来我创建 SQLite 连接并请求
var cmd = new SQLiteCommand("SELECT encrypted_value, name FROM cookies WHERE host_key = 'my_host_ip'", con);
然后我阅读结果
byte[] encryptedCookie = (byte[])r.GetValue(r.GetOrdinal("encrypted_value"));
并尝试解密它:
var decodedData = ProtectedData.Unprotect(encryptedCookie, null, DataProtectionScope.CurrentUser);
var plainText = Encoding.ASCII.GetString(decodedData);
这里我遇到了异常
System.Security.Cryptography.CryptographicException
我知道我必须在启动浏览器的同一用户帐户下(在同一台机器上)解密 cookie 内容,并为此使用参数 DataProtectionScope.CurrentUser
我在调试器中看到了 63 个字节(在 encryptedCookie 数组中),我还在 SQLite DB BLOB 字段中看到了这个字节。
但是Unprotect 方法会抛出System.Security.Cryptography.CryptographicException: Invalid data 错误。
我的代码在我办公室的 5 台不同的 PC 上运行良好(win10、win7),但在我的开发人员 PC 上无法运行(win10、vs2019)。
我认为问题出在我的 Windows 设置或其他地方,而不是我的代码中。那我做错了什么?
有趣的注释——我发现了做同样事情的 PowerShell 脚本(通过Add-Type -AssemblyName System.Security)——获取 cookie 并解密它。此脚本在 5 台办公室 PC 上也可以正常工作,但在我的 PC 上无法正常工作。
我的 Windows 安装是新的,我没有 AV 软件。我们连接到同一个企业域并且我们具有相同的安全设置。
UPD 1 一个小实验:
- 从 Chrome 浏览器获取 cookie 值(32 个字符,JSESSIONID)
- 创建一个简单的应用程序,使用
CurrentUser保护范围保护此值。现在我有一个 178 字节的数组(结果 #1) - 使用 a) https://sqliteonline.com/ 和 b) DataBase.Net 桌面应用程序查看 Chrome 的 cookie 数据库。这两种方法给了我相同的结果:只有 63 字节的加密 cookie 数据(结果 #2)。我也可以使用
System.Data.SQLite在我的 c# 应用程序中获得相同的结果
所以,结果的长度或内容不相等 结果 #1 != 结果 #2
看起来 Chrome 的 cookie 值受不同范围保护(可能是管理员帐户?),但我在 Chrome 进程的任务管理器中看到我的用户帐户名称
附:我使用.net 4.7.2
UPD 2 我在 Chromium 资源中找到了这种方法
bool OSCrypt::DecryptString(const std::string& ciphertext,
std::string* plaintext) {
if (!base::StartsWith(ciphertext, kEncryptionVersionPrefix,
base::CompareCase::SENSITIVE))
return DecryptStringWithDPAPI(ciphertext, plaintext);
crypto::Aead aead(crypto::Aead::AES_256_GCM);
auto key = GetEncryptionKeyInternal();
aead.Init(&key);
// Obtain the nonce.
std::string nonce =
ciphertext.substr(sizeof(kEncryptionVersionPrefix) - 1, kNonceLength);
// Strip off the versioning prefix before decrypting.
std::string raw_ciphertext =
ciphertext.substr(kNonceLength + (sizeof(kEncryptionVersionPrefix) - 1));
return aead.Open(raw_ciphertext, nonce, std::string(), plaintext);
}
所以 DPAPI 仅在 BLOB NOT 以 v10 字符开头时使用。但是我的 cookie BLOB 以 v10 字符开头,并且根据代码,使用了另一种加密算法,但我不明白为什么。
【问题讨论】:
-
我首先要让 MySQL 脱离循环——你能加密然后解密你计算机上的任意字节数组吗?只需调用 Protect 然后 Unprotect 结果。
-
@JonSkeet 是的,我创建了一个简单的示例,我在其中保护数据数组,然后在一个控制台应用程序中使用相同的熵(null)和相同的密钥取消保护它。一切正常
-
所以你需要弄清楚事情链的哪一步失败了。首先确保您可以完全可靠地重现它 - 然后您可以在输入和输出的过程中记录字节(例如使用 base64 获取 ASCII),并查看它们的变化。
-
没有 .NET 7.2。也许您的意思是您使用的是确实存在的 C# 7.2。 .NET 和 C# 版本目前完全不同。
-
我真的不知道 - 我不能完全按照您正在经历的步骤,或者数据的来源。希望其他人能够为您提供更多帮助。