python - Chrome 80 如何解码 cookie
问题描述
我有一个用于打开和解密 Google Chrome cookie 的工作脚本,如下所示:
decrypted = win32crypt.CryptUnprotectData(enctypted_cookie_value, None, None, None, 0)
似乎在更新 80 之后它不再是一个有效的解决方案。
根据这篇博客文章https://blog.nirsoft.net/2020/02/19/tools-update-new-encryption-chrome-chromium-version-80/看来我需要从本地状态文件中对 encrypted_key 进行 CryptUnprotectData ,而不是使用解密的密钥以某种方式解密 cookie。
第一部分我得到了我的 encrypted_key
path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = bytearray(encrypted_key, 'utf-8')
然后我试图解密它
解密密钥 = win32crypt.CryptUnprotectData(加密密钥,无,无,无,0)
并得到了例外:
pywintypes.error: (13, 'CryptProtectData', 'The data is invalid.')
我不知道如何解决它
同样对于加密的第二部分,我似乎应该使用 pycryptodome,类似于以下代码片段:
cipher = AES.new(encrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt(data)
但我不知道我应该在哪里获得 nonce 值
有人可以解释一下,如何正确解密 Chrome cookie?
解决方案
从 Chrome 80 及更高版本开始,cookie 在 GCM 模式下使用 AES-256 进行加密。应用的密钥使用 DPAPI 加密。详细信息在此处描述,Chrome v80.0 和更高版本。
加密的密钥以DPAPI
(ie 0x4450415049
) 的 ASCII 编码开始并且是 Base64 编码的,即密钥必须首先进行 Base64 解码,并且必须删除前 5 个字节。之后可以进行解密win32crypt.CryptUnprotectData
。解密返回一个元组,其第二个值包含解密的密钥:
import os
import json
import base64
import win32crypt
from Crypto.Cipher import AES
path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = base64.b64decode(encrypted_key) # Base64 decoding
encrypted_key = encrypted_key[5:] # Remove DPAPI
decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1] # Decrypt key
cookie 的加密是在GCM 模式下使用AES-256执行的。这是经过身份验证的加密,可保证机密性和真实性/完整性。在加密期间会生成一个身份验证标签,用于在解密期间进行完整性验证。GCM 模式基于 CTR 模式并使用 IV(nonce)。除了 32 字节的密钥外,解密还需要随机数和身份验证标签。
加密数据以v10
(ie 0x763130
) 的 ASCII 编码开始,接着是 12 字节的随机数、实际的密文,最后是 16 字节的认证标签。可以按如下方式分离各个组件:
data = bytes.fromhex('763130...') # the encrypted cookie
nonce = data[3:3+12]
ciphertext = data[3+12:-16]
tag = data[-16:]
其中data
包含加密的数据。解密本身是使用PyCryptodome完成的:
cipher = AES.new(decrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag) # the decrypted cookie
注意:一般情况下,也有存储的 cookie 是用 v80 以下的 Chrome 版本保存的,因此是 DPAPI 加密的。DPAPI 加密的 cookie 可以通过它们以序列开头的事实来识别0x01000000D08C9DDF0115D1118C7A00C04FC297EB
,这里和这里,关于 DPAPI部分。这些 cookie 当然不能像上面描述的那样被解密,但是可以通过 DPAPI 加密 cookie 的前一个过程来解密。以未加密或加密形式查看 cookie 的工具分别是ChromeCookiesView或DB Browser for SQLite。
推荐阅读
- android - 'com.google.android.gms:play-services-base' 对于编译(15.0.1)和运行时(16.0.1)有不同
- javascript - javascript函数回调,参数(错误,响应,正文)顺序重要吗?
- c# - json函数不调用控制器
- activerecord - ActiveStorage blob 文件名上的 Rails 范围会给出错误的结果
- symfony - 表单不向数据库发送数据
- javascript - jquery如何添加焦点和悬停效果
- php - 如何使用php替换嵌套引号中的双引号
- bootstrap-4 - RAILS 5 上的邪恶 PDF 忽略 bootstrap 4 网格系统
- keras - 加载 Keras 中 callbakcs.ModelCheckpoint() 保存的模型时出错
- javascript - DHTMLX 甘特图不在后台引导选项卡中呈现