Cookie crittografati in Chrome

Attualmente sto lavorando a un’applicazione di moduli C # che deve accedere a un cookie specifico sul mio computer, che posso fare perfettamente. Ecco il problema:

Google memorizza i cookie in SQLite e ho scaricato il browser di database Sqlite per aiutarmi a guardare questi valori. Ciò che mi sorprende è che circa la metà dei valori dei cookie è vuota (inclusa quella di cui ho bisogno), anche se ovviamente non lo sono.

Il file db si trova in:

C:\Users\%username%\AppData\Local\Google\Chrome\User Data\Default\Cookies 

Su Chrome ho un addon chiamato “Modifica questo cookie” che mi consente di modificare direttamente i cookie sul sito web in cui mi trovo. Questo addon può leggere questi cookie e il browser Web può analizzare i valori tramite HTTP quando necessario per richieste diverse, quindi sono sicuramente lì – tuttavia, il browser SQLite e il mio codice personalizzato arrivano entrambi alla conclusione che il campo del valore particolare è vuoto .

Perché? Che cosa impedisce in qualche modo la lettura del campo da parte di determinate applicazioni?

Ho incontrato questo stesso problema e il codice seguente fornisce un esempio funzionante per chiunque sia interessato. Tutto merito a Scherling, dato che il DPAPI era perfetto.

 public class ChromeCookieReader { public IEnumerable> 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(); } } } 

Bene, quindi nel caso qualcuno fosse interessato, ho trovato una soluzione a questo problema dopo un sacco di tentativi, errori e googling.

Cookie di Google Chrome Il DB ha due colonne per la memorizzazione dei valori: “valore” e “valore crittografato”, quest’ultimo utilizzato quando il cookie memorizzato è stato richiesto per essere crittografato, spesso nel caso di determinate informazioni riservate e chiavi di sessione di lunga durata.

Dopo averlo capito, ho quindi dovuto trovare un modo per accedere a questa chiave, memorizzata come valore Blob. Ho trovato diverse guide su come fare questo, ma quello che ha finito per pagare era: http://www.codeproject.com/Questions/56109/Reading-BLOB-in-Sqlite-using-C-NET-CF- PPC

Basta leggere il valore non è sufficiente, in quanto è crittografato. – Google Chrome utilizza la tripla crittografia DES con la password degli utenti correnti come seed su macchine Windows. Per decifrare questo in C #, si dovrebbe usare l’API di Windows Data Protection (DPAPI), ci sono alcune guide là fuori su come utilizzarlo.

Come la risposta di Jasper, in uno script PowerShell (ovviamente, personalizzare la query SQL in base alle proprie esigenze e il percorso della posizione dei 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 
  # 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 

Quindi volevo farlo senza scrivere in un tempfile ogni volta, ma anche senza implementare una class separata come per la soluzione di jasper. Come jasper , ho trovato più facile e veloce accedere al System.Data.SQLite.dll disponibile qui . Non è elegante come una class separata, ma è quello che ha funzionato meglio per me:

 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 

Ho anche trovato che la funzione Add-SqliteAssembly di halr9000 è molto utile quando è arrivato il momento di programmare il mio script nell’utilità di pianificazione di Windows e ho capito che l’utilità di pianificazione esegue la versione x86 di PowerShell e quindi SQLite anziché x64 che stavo usando in la console.

Basta impostare “valore” sul cookie che si desidera, “valore_criptato” su NULL e “priorità” su 0