web-dev-qa-db-ja.com

Chrome内の暗号化されたCookie

私は現在、自分のコンピューター上の特定のCookieにアクセスする必要があるC#フォームアプリケーションに取り組んでいます。ここに問題があります:

GoogleはCookieをSQLiteに保存し、これらの値を確認するためにSqliteデータベースブラウザーをダウンロードしました。驚いたのは、Cookieの値の約半分が空である(必要なものを含む)と表示されていることです。

Dbファイルは次の場所にあります。

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

Chrome私は「このCookieを編集」と呼ばれるアドオンを持っています。これにより、自分がいるWebサイトのCookieを直接変更できます。このアドオンはこれらのCookieを読み取ることができ、Webブラウザは値を解析できますさまざまな要求に必要なときにHTTP経由で送信されるため、それらは確実に存在します。それでも、SQLiteブラウザーと私のカスタムコードはどちらも、特定の値フィールドが空であるという結論に達します。

何故ですか?特定のアプリケーションがフィールドを読み取れないのはなぜですか?

19
Scherling

申し訳ありませんが、誰かが興味を持っている場合に備えて、試行錯誤、グーグルを繰り返した結果、この問題の解決策を見つけました。

Google Chrome cookies DBには値を格納するための2つの列があります: "value"と "encrypted_value"、後者は格納されたcookieの暗号化が要求されたときに使用されます-多くの場合、特定の機密情報と長時間のセッションキー。

これを理解した後、Blob値として保存されているこのキーにアクセスする方法を見つける必要がありました。私はこれを行う方法についていくつかのガイドを見つけましたが、最終的に支払ったのは http://www.codeproject.com/Questions/56109/Reading-BLOB-in-Sqlite-using-C- NET-CF-PPC

暗号化されているため、単に値を読み取るだけでは不十分です。 -Google Chromeは、Windowsマシンでシードとして現在のユーザーパスワードを使用してトリプルDES暗号化を使用します。これをC#で復号化するには、Windowsデータ保護を使用する必要があります。 API(DPAPI)、それを利用する方法についていくつかのガイドがあります。

13
Scherling

私はこれと同じ問題に遭遇しました、そして以下のコードは興味がある人のための実用的な例を提供します。 DPAPIがスポットされていたため、Scherlingへのすべての貢献。

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();
        }
    }
}
28
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
7
dgtc

したがって、毎回一時ファイルに書き込むことなく、ジャスパーのソリューションに従って別のクラスを実装することなく、これを実行したいと思いました。 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 function by halr90 は、Windowsタスクスケジューラでスクリプトをスケジュールするときに非常に役立ち、タスクスケジューラがx86を実行していることにも気付きました。 PowerShellのバージョン、つまりコンソールで使用していたx64ではなくSQLite。

1
mjblay
    # 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
0
Yordan Georgiev