1. 项目背景与核心挑战
某9安全中心的登录机制采用了典型的动态参数加密方案,其中最关键的就是这个神秘的"d"值参数。这个参数通常由前端JavaScript生成,包含时间戳、设备指纹、行为特征等多重信息,经过复杂的加密算法处理后提交给服务器验证。
在实际逆向过程中,我们发现这个d值具有以下特征:
- 每次登录请求都会变化
- 长度固定为32位字符
- 包含大小写字母和数字组合
- 与用户操作行为存在关联性
重要提示:本文仅用于技术研究和学习目的,所有分析过程均基于公开可访问的网页前端代码,不涉及任何越权操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 逆向分析环境准备
2.1 工具链配置
工欲善其事必先利其器,以下是经过实战验证的工具组合:
-
浏览器开发者工具(Chrome DevTools)
- Elements面板:查看DOM结构
- Network面板:捕获请求流量
- Sources面板:调试JavaScript
- Console面板:执行临时代码
-
辅助工具
- Fiddler/Charles:网络请求抓包
- Node.js环境:本地执行调试JS代码
- Python requests库:模拟请求验证
-
逆向专用工具
- AST Explorer:解析JavaScript抽象语法树
- WebStorm/VSCode:代码分析与格式化
- Hook工具:函数调用追踪
2.2 关键分析步骤
- 打开目标登录页面,清空浏览器缓存
- 开启开发者工具的Preserve log功能
- 执行一次完整的登录操作
- 在Network面板筛选XHR请求,找到登录接口
- 查看请求参数,定位到d值参数
3. d值生成逻辑深度解析
3.1 调用栈追踪
通过调试发现d值的生成路径如下:
code复制loginButton.click → submitForm() → encryptParams() → generateDValue() → window.cryptoAPI.encrypt()
关键突破点在于generateDValue函数,其核心逻辑包含三个部分:
- 基础参数收集
javascript复制function collectBaseParams() {
return {
t: Date.now(), // 时间戳
ua: navigator.userAgent,
screen: `${window.screen.width}x${window.screen.height}`,
referrer: document.referrer || '',
// 其他环境参数...
}
}
- 行为特征提取
javascript复制function getBehaviorFingerprint() {
const mouseTrack = window.mouseTrackBuffer || [];
const clickPattern = analyzeClickPattern(mouseTrack);
return {
clickCount: clickPattern.count,
moveSpeed: clickPattern.avgSpeed,
// 其他行为特征...
};
}
- 加密处理流程
javascript复制function encryptData(rawData) {
const salt = generateRandomSalt();
const key = deriveKey(salt);
const iv = crypto.getRandomValues(new Uint8Array(16));
return {
ciphertext: window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
new TextEncoder().encode(JSON.stringify(rawData))
),
salt,
iv
};
}
3.2 核心加密算法还原
通过AST分析,我们还原出完整的加密流程:
- PBKDF2密钥派生
javascript复制async function deriveKey(salt) {
const baseKey = await window.crypto.subtle.importKey(
"raw",
new TextEncoder().encode("baseSecretKey"),
{ name: "PBKDF2" },
false,
["deriveKey"]
);
return await window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 10000,
hash: "SHA-256"
},
baseKey,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
}
- AES-GCM加密
javascript复制async function finalEncrypt(data) {
const encrypted = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: new Uint8Array(16),
additionalData: new TextEncoder().encode("authData"),
tagLength: 128
},
data.key,
data.plaintext
);
return arrayBufferToBase64(encrypted);
}
4. Python实现方案
4.1 加密逻辑移植
python复制from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Random import get_random_bytes
import base64
import json
import time
def generate_d_value():
# 1. 收集基础参数
params = {
"t": int(time.time() * 1000),
"ua": "Mozilla/5.0...",
"screen": "1920x1080",
# 其他参数...
}
# 2. 密钥派生
salt = get_random_bytes(16)
key = PBKDF2(
password=b"baseSecretKey",
salt=salt,
dkLen=32,
count=10000,
hmac_hash_module=SHA256
)
# 3. AES加密
iv = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
cipher.update(b"authData")
ciphertext, tag = cipher.encrypt_and_digest(
json.dumps(params).encode()
)
# 4. 组合最终d值
result = {
"ciphertext": base64.b64encode(ciphertext).decode(),
"salt": base64.b64encode(salt).decode(),
"iv": base64.b64encode(iv).decode(),
"tag": base64.b64encode(tag).decode()
}
return base64.b64encode(json.dumps(result).encode()).decode()
4.2 请求模拟实现
python复制import requests
def simulate_login(username, password):
session = requests.Session()
# 1. 获取初始token
init_resp = session.get("https://xxx.com/getToken")
token = init_resp.json()["token"]
# 2. 生成d值
d_value = generate_d_value()
# 3. 构造登录请求
login_data = {
"username": username,
"password": encrypt_password(password),
"d": d_value,
"token": token
}
# 4. 发送请求
response = session.post(
"https://xxx.com/login",
json=login_data,
headers={
"User-Agent": "Mozilla/5.0...",
"X-Requested-With": "XMLHttpRequest"
}
)
return response.json()
5. 常见问题与解决方案
5.1 加密结果不一致问题
现象:Python生成的d值与浏览器生成的不匹配
排查步骤:
- 检查时间戳精度(浏览器使用毫秒级)
- 验证PBKDF2参数是否一致(迭代次数、哈希算法)
- 确认AES模式配置(GCM需要auth data)
- 检查base64编码方式(是否URL安全)
解决方案:
python复制# 修正后的时间戳获取
timestamp = int(time.time() * 1000)
# 确保编码一致
def safe_b64encode(data):
return base64.b64encode(data).decode().replace("+", "-").replace("/", "_")
5.2 反爬虫机制应对
常见防御手段:
- 请求频率限制
- 行为指纹检测
- TLS指纹校验
- 环境参数验证
绕过方案:
python复制# 使用真实浏览器环境
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
def get_real_browser_d_value():
options = Options()
options.add_argument("--disable-blink-features=AutomationControlled")
driver = Chrome(options=options)
driver.get("https://xxx.com/login")
d_value = driver.execute_script("return window.generateDValue()")
driver.quit()
return d_value
6. 高级技巧与优化
6.1 性能优化方案
- 预计算静态参数:
python复制# 预先计算不变的参数
STATIC_PARAMS = {
"ua": "Mozilla/5.0...",
"screen": "1920x1080",
# 其他静态参数...
}
def quick_generate_d_value():
params = {**STATIC_PARAMS, "t": int(time.time() * 1000)}
# 快速加密流程...
- 多级缓存策略:
- 内存缓存最近5分钟的d值
- 本地存储加密密钥
- 复用HTTP会话
6.2 动态参数增强
对于更严格的安全校验,可能需要补充:
python复制def enhance_dynamic_params():
return {
"pointerEvents": get_pointer_events(),
"fontFingerprint": get_font_fingerprint(),
"webGLParams": get_webgl_params(),
# 其他高级指纹...
}
7. 法律与伦理边界
在实施此类技术时,必须注意:
- 合规要求:
- 严格遵守目标网站的robots.txt规则
- 控制请求频率(建议≥5秒/次)
- 仅采集公开可用数据
- 伦理准则:
- 不绕过付费墙
- 不获取用户隐私数据
- 不用于商业牟利
- 技术防护:
python复制# 添加合规延迟
import random
time.sleep(random.uniform(5, 10))
