我目前正在开发一个C#表单应用程序,需要访问我计算机上的特定cookie,我可以做得非常好。问题在于:
Google将Cookie存储在SQLite中,我已经下载了Sqlite数据库浏览器以帮助我查看这些值。令我惊讶的是,大约一半的cookie值显示为空(包括我需要的那些),即使它们显然不是。
db文件位于:
C:\Users\%username%\AppData\Local\Google\Chrome\User Data\Default\Cookies
在Chrome上我有一个名为"编辑此Cookie的插件"这允许我直接修改我所在网站上的cookie。这个插件可以读取这些cookie,并且Web浏览器可以在需要时通过HTTP解析不同的请求,因此它们肯定存在 - 仍然,SQLite浏览器和我的自定义代码都得出结论,特定值字段为空
为什么? 是什么以某种方式阻止某些应用程序读取该字段?
答案 0 :(得分:27)
我遇到了同样的问题,下面的代码为有兴趣的人提供了一个工作示例。所有信用都归功于Scherling,因为DPAPI是现货。
public class ChromeCookieReader
{
public IEnumerable<Tuple<string,string>> ReadCookies(string hostName)
{
if (hostName == null) throw new ArgumentNullException("hostName");
var dbPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Google\Chrome\User Data\Default\Cookies";
if (!System.IO.File.Exists(dbPath)) throw new System.IO.FileNotFoundException("Cant find cookie store",dbPath); // race condition, but i'll risk it
var connectionString = "Data Source=" + dbPath + ";pooling=false";
using (var conn = new System.Data.SQLite.SQLiteConnection(connectionString))
using (var cmd = conn.CreateCommand())
{
var prm = cmd.CreateParameter();
prm.ParameterName = "hostName";
prm.Value = hostName;
cmd.Parameters.Add(prm);
cmd.CommandText = "SELECT name,encrypted_value FROM cookies WHERE host_key = @hostName";
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var encryptedData = (byte[]) reader[1];
var decodedData = System.Security.Cryptography.ProtectedData.Unprotect(encryptedData, null, System.Security.Cryptography.DataProtectionScope.CurrentUser);
var plainText = Encoding.ASCII.GetString(decodedData); // Looks like ASCII
yield return Tuple.Create(reader.GetString(0), plainText);
}
}
conn.Close();
}
}
}
答案 1 :(得分:13)
好吧,如果有人有兴趣,我在经过多次试用,错误和谷歌搜索后找到了解决这个问题的方法。
Google Chrome Cookie数据库有2列用于存储值:&#34;值&#34;和#34; encrypted_value&#34;,当存储的cookie被请求加密时使用后者 - 通常是某些机密信息和长时间会话密钥的情况。
在搞清楚之后,我需要找到一种方法来访问此密钥,存储为Blob值。我找到了几个关于如何做到这一点的指南,但最终支付的是:http://www.codeproject.com/Questions/56109/Reading-BLOB-in-Sqlite-using-C-NET-CF-PPC
仅仅读取值是不够的,因为它是加密的。 - Google Chrome使用三重DES加密,当前用户密码作为Windows计算机上的种子。为了在C#中解密,应该使用Windows数据保护API(DPAPI),有一些关于如何使用它的指南。
答案 2 :(得分:7)
与Jasper的答案一样,在PowerShell脚本中(当然,根据您的需要自定义SQL查询,以及Cookie位置的路径):
$cookieLocation = 'C:\Users\John\AppData\Local\Google\Chrome\User Data\Default\cookies'
$tempFileName = [System.IO.Path]::GetTempFileName()
"select writefile('$tempFileName', encrypted_value) from cookies where host_key = 'localhost' and path = '/api' and name = 'sessionId';" | sqlite3.exe "$cookieLocation"
$cookieAsEncryptedBytes = Get-Content -Encoding Byte "$tempFileName"
Remove-Item "$tempFileName"
Add-Type -AssemblyName System.Security
$cookieAsBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($cookieAsEncryptedBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
$cookie = [System.Text.Encoding]::ASCII.GetString($cookieAsBytes)
$cookie
答案 3 :(得分:1)
因此,我希望每次都不写入临时文件而不按照jasper的解决方案实现单独的类。与jasper一样,我发现访问System.Data.SQLite.dll可用here更容易,更快捷。它不像一个单独的类那么优雅,但它最适合我:
Add-Type -AssemblyName System.Security
Add-Type -Path 'C:\Program Files\System.Data.SQLite\2015\bin\x64\System.Data.SQLite.dll'
Function Get-Last-Cookie {
Param(
[Parameter(Mandatory=$True)] $valueName,
[Parameter(Mandatory=$True)] $hostKey,
[Parameter(Mandatory=$True)] $dbDataSource
)
$conn = New-Object -TypeName System.Data.SQLite.SQLiteConnection
$conn.ConnectionString = "Data Source=$dbDataSource"
$conn.Open()
$command = $conn.CreateCommand()
$query = "SELECT encrypted_value FROM cookies WHERE name='$valueName' `
AND host_key='$hostKey' ORDER BY creation_utc DESC LIMIT 1"
$command.CommandText = $query
$adapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter $command
$dataset = New-Object System.Data.DataSet
[void]$adapter.Fill($dataset)
$command.Dispose();
$conn.Close();
$cookieAsEncryptedBytes = $dataset.Tables[0].Rows[0].ItemArray[0]
$cookieAsBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($cookieAsEncryptedBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
return [System.Text.Encoding]::ASCII.GetString($cookieAsBytes)
}
$localAppDataPath = [Environment]::GetFolderPath([Environment+SpecialFolder]::LocalApplicationData)
$cookieDbPath = 'Google\Chrome\User Data\Default\Cookies'
$dbDataSource = Join-Path -Path $localAppDataPath -ChildPath $cookieDbPath
$plainCookie = Get-Last-Cookie 'acct' '.stackoverflow.com' $dbDataSource
Write-Host $plainCookie
我还发现Add-SqliteAssembly的halr9000函数非常有用,因为我需要在Windows任务调度程序中安排我的脚本,并意识到任务调度程序运行PowerShell的x86版本,因此SQLite而不是我在控制台中使用的x64。
答案 4 :(得分:0)
# this powershell scripts exports your cookies to a format curl and wget understand
# Obs ! Each profile has its own cookes file , replace me (ysg ;o) with your win usr name
# aka wget -x --load-cookies cookies.txt http://stackoverflow.com/questions/22532870/encrypted-cookies-in-chrome
$cookieLocation = 'C:\Users\ysg\AppData\Local\Google\Chrome\User Data\Profile 1\Cookies'
$curl_cookies_file="C:\var\ygeo.reports.app.futurice.com.cookies.doc-pub-host.txt"
$tempFileName1 = [System.IO.Path]::GetTempFileName()
$tempFileName2 = [System.IO.Path]::GetTempFileName()
# adjust your filter in the where clause ...
"select writefile('$tempFileName1', encrypted_value) from cookies where host_key = '.futurice.com' ;" | sqlite3.exe "$cookieLocation"
$cookieAsEncryptedBytes = Get-Content -Encoding Byte "$tempFileName1"
Remove-Item "$tempFileName1"
Add-Type -AssemblyName System.Security
$cookieAsBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($cookieAsEncryptedBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
$cookie = [System.Text.Encoding]::ASCII.GetString($cookieAsBytes)
$unquoted_cookie=$cookie -replace '"', ""
# adjust your filter in the where clause ...
"
select
host_key
, CASE WHEN httponly=0 THEN 'FALSE' ELSE 'TRUE' END
, path
, CASE WHEN secure=0 THEN 'FALSE' ELSE 'TRUE' END
, expires_utc
, name
, '$unquoted_cookie'
from cookies where host_key = '.futurice.com' ;" | sqlite3.exe -separator " " "$cookieLocation" > $curl_cookies_file
Get-ChildItem *.txt | ForEach-Object { (Get-Content $_) | Out-File -Encoding ASCII $_ }
# check the meta data table
#"PRAGMA table_info([cookies]);" | sqlite3.exe "$cookieLocation"
# src: https://github.com/daftano/cookies.txt/blob/master/src/popup.js
#content += escapeForPre(cookie.domain);
#content += "\t";
#content += escapeForPre((!cookie.hostOnly).toString().toUpperCase());
#content += "\t";
#content += escapeForPre(cookie.path);
#content += "\t";
#content += escapeForPre(cookie.secure.toString().toUpperCase());
#content += "\t";
#content += escapeForPre(cookie.expirationDate ? Math.round(cookie.expirationDate) : "0");
#content += "\t";
#content += escapeForPre(cookie.name);
#content += "\t";
#content += escapeForPre(cookie.value);
#content += "\n";
#
#0|creation_utc|INTEGER|1||1
#1|host_key|TEXT|1||0
#2|name|TEXT|1||0
#3|value|TEXT|1||0
#4|path|TEXT|1||0
#5|expires_utc|INTEGER|1||0
#6|secure|INTEGER|1||0
#7|httponly|INTEGER|1||0
#8|last_access_utc|INTEGER|1||0
#9|has_expires|INTEGER|1|1|0
#10|persistent|INTEGER|1|1|0
#11|priority|INTEGER|1|1|0
#12|encrypted_value|BLOB|0|''|0
#13|firstpartyonly|INTEGER|1|0|0
答案 5 :(得分:0)
问题是谷歌浏览器会加密您需要阅读的数据,因此您必须对其进行解密。 首先,获取 cookie 文件的副本。然后使用 SQLite3 读取它。之后,获取加密的字节。最后,使用下面的代码来解密它。 您将需要这些 Nuget:
using System.IO;
using System.Net;
using System.Data.SQLite;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Newtonsoft.Json.Linq;
目前的代码:
File.Copy(Environment.GetEnvironmentVariable("APPDATA") + @"/../Local/Google/Chrome/User Data/Default/Cookies", @"./Cookies",true);
SQLiteConnection Cnn = new SQLiteConnection("Data Source=" + @"./Cookies" + ";pooling=false");
Cnn.Open();
SQLiteCommand cmd = new SQLiteCommand("SELECT host_key, name, value, encrypted_value FROM cookies WHERE name='mvrusername' OR name='mvrcookie' OR name='mikuki4'", Cnn);
SQLiteDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
byte[] encryptedData = (byte[])rdr["encrypted_value"];
string encKey = File.ReadAllText(Environment.GetEnvironmentVariable("APPDATA") + @"/../Local/Google/Chrome/User Data/Local State");
encKey = JObject.Parse(encKey)["os_crypt"]["encrypted_key"].ToString();
var decodedKey = System.Security.Cryptography.ProtectedData.Unprotect(Convert.FromBase64String(encKey).Skip(5).ToArray(), null, System.Security.Cryptography.DataProtectionScope.LocalMachine);
const int MAC_BIT_SIZE = 128;
const int NONCE_BIT_SIZE = 96;
using (var cipherStream = new MemoryStream(encryptedData))
using (var cipherReader = new BinaryReader(cipherStream))
{
var nonSecretPayload = cipherReader.ReadBytes(3);
var nonce = cipherReader.ReadBytes(NONCE_BIT_SIZE / 8);
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(decodedKey), MAC_BIT_SIZE, nonce);
cipher.Init(false, parameters);
var cipherText = cipherReader.ReadBytes(encryptedData.Length);
var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];
try
{
var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
cipher.DoFinal(plainText, len);
}
catch (InvalidCipherTextException)
{
}
string _cookie= Encoding.Default.GetString(plainText);
}
}
// 非常感谢 https://stackoverflow.com/a/60611673/6481581 回答 Chrome 80 及更高版本如何改变 cookie 的加密方式。
答案 6 :(得分:-5)
只需设置&#34;值&#34;到你想要的cookie,&#34; encrypted_value&#34;为NULL和&#34;优先级&#34;到0