先说结论,MacOS
上的Chrome Cookie
保存方式为Sqlite
,对应的表名为cookies
,数据的加密方式为AES + PBKDF2 + SHA1
。
Cookie存储路径 MacOS
下Chrome Cookie
保存方式为Sqlite
文件,存储的路径为:
1 ~/Library/Application Support/Google/Chrome/Default/Cookies
Cookie表结构 我们通过sqlite
读取Cookies
文件后,可以查看cookies
表结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 CREATE TABLE cookies( creation_utc INTEGER NOT NULL , host_key TEXT NOT NULL , top_frame_site_key TEXT NOT NULL , name TEXT NOT NULL , value TEXT NOT NULL , encrypted_value BLOB NOT NULL , path TEXT NOT NULL , expires_utc INTEGER NOT NULL , is_secure INTEGER NOT NULL , is_httponly INTEGER NOT NULL , last_access_utc INTEGER NOT NULL , has_expires INTEGER NOT NULL , is_persistent INTEGER NOT NULL , priority INTEGER NOT NULL , samesite INTEGER NOT NULL , source_scheme INTEGER NOT NULL , source_port INTEGER NOT NULL , last_update_utc INTEGER NOT NULL , source_type INTEGER NOT NULL , has_cross_site_ancestor INTEGER NOT NULL )
其中encrypted_value
就是网站的cookie
值,但是这个值是加密后的值,我们需要进行解密。
Cookie解密 获取密钥 此处我们可以通过终端命令获取解密密钥,过程中可能需要输入登录密码 :
1 2 yi@23456 ~ % security find-generic-password -wga Chrome Exxxxabccsssx==
解密 解密方式为AES
,密钥生成方式为PBKDF2
,底层哈希使用SHA1
,以Java
为例,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 String salt = "saltysalt" ; String iv = String.format("%" + 16 + "s" , "" ); int length = 128 ; String password = "Exxxxabccsssx==" ; int iterations = 1003 ; SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1" );PBEKeySpec keySpec = new PBEKeySpec (password.toCharArray(), salt.getBytes(), iterations, length);SecretKeySpec secretKeySpec = new SecretKeySpec (keyFactory.generateSecret(keySpec).getEncoded(), "AES" );IvParameterSpec ivSpec = new IvParameterSpec (iv.getBytes());Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding" );cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec); byte [] cookieBytes = cipher.doFinal(Arrays.copyOfRange(encryptedValueBytes, 3 , encryptedValueBytes.length));System.out.println(new String (cookieBytes));
完整代码 Java
完整示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import javax.crypto.Cipher;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.PBEKeySpec;import javax.crypto.spec.SecretKeySpec;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;import java.util.Arrays;public class ChromeCookieTest { public static void main (String[] args) throws Exception { Class.forName("org.sqlite.JDBC" ); String cookiePath = "本地Cookie路径" ; String password = "解密密钥" ; try (Connection con = DriverManager.getConnection("jdbc:sqlite:" + cookiePath); Statement statement = con.createStatement()) { ResultSet resultSet = statement.executeQuery("select encrypted_value from cookies where host_key like '%host_name%' and name = 'cookie_name'" ); byte [] encryptedValueBytes = (byte []) resultSet.getObject(1 ); String salt = "saltysalt" ; String iv = String.format("%" + 16 + "s" , "" ); int length = 128 ; int iterations = 1003 ; SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1" ); PBEKeySpec keySpec = new PBEKeySpec (password.toCharArray(), salt.getBytes(), iterations, length); SecretKeySpec secretKeySpec = new SecretKeySpec (keyFactory.generateSecret(keySpec).getEncoded(), "AES" ); IvParameterSpec ivSpec = new IvParameterSpec (iv.getBytes()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding" ); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec); byte [] cookieBytes = cipher.doFinal(Arrays.copyOfRange(encryptedValueBytes, 3 , encryptedValueBytes.length)); System.out.println(new String (cookieBytes)); } } }
参考 https://gist.github.com/dacort/bd6a5116224c594b14db