Зашифрованные файлы cookie в Chrome
В настоящее время я работаю над приложением форм С#, которому необходимо получить доступ к определенному файлу cookie на моем компьютере, что я могу сделать отлично. Здесь проблема:
Google хранит файлы cookie в SQLite, и я загрузил браузер базы данных Sqlite, чтобы помочь мне взглянуть на эти значения. Меня удивляет то, что примерно половина значений cookie отображается как пустая (в том числе и та, которая мне нужна), хотя они явно не являются.
Файл db находится по адресу:
C:\Users\%username%\AppData\Local\Google\Chrome\User Data\Default\Cookies
В Chrome у меня есть аддон под названием "Edit This Cookie", который позволяет мне напрямую изменять файлы cookie на веб-сайте, на котором я нахожусь. Этот аддон может читать эти куки файлы, и веб-браузер может анализировать значения через HTTP, когда это необходимо для разных запросов, поэтому они определенно существуют. Тем не менее, браузер SQLite и мой пользовательский код приходят к выводу, что поле специального значения пустое.
Почему?
Что это значит, что каким-то образом препятствует чтению поля определенными приложениями?
Ответы
Ответ 1
Хорошо, поэтому в случае, если кто-то заинтересован, я нашел решение этой проблемы после многих проб, ошибок и googling.
БД Google cookie Google содержит 2 столбца для хранения значений: "value" и "encrypted_value", последний используется, когда хранимый файл cookie был запрошен для шифрования - часто бывает с определенной конфиденциальной информацией и длительными сеансовыми ключами.
После выяснения этого, мне тогда нужно было найти способ доступа к этому ключу, который хранится как значение Blob. Я нашел несколько руководств о том, как это сделать, но тот, который закончился оплатой, был: http://www.codeproject.com/Questions/56109/Reading-BLOB-in-Sqlite-using-C-NET-CF-PPC
Простое чтение значения недостаточно, поскольку оно зашифровано. - Google Chrome использует тройное шифрование DES с текущим паролем пользователей как семя на машинах Windows. Чтобы расшифровать это на С#, следует использовать API защиты данных Windows (DPAPI), есть несколько руководств о том, как его использовать.
Ответ 2
Я столкнулся с этой же проблемой, и приведенный ниже код представляет собой рабочий пример для всех, кто заинтересован. Весь кредит для Шерлинга, поскольку 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();
}
}
}
Ответ 3
Как и ответ Джаспера, в PowerShell script (конечно, настройте 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
Ответ 4
# 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
Просто установите "значение" для файла cookie, который вы хотите, "encrypted_value" в NULL, а "priority" - 0