目录
- 常见前端加密场景
- 定位加密方法的技术
- 寻找密钥和盐的方法
- 常用工具
- 案例分析
- 防御措施
常见前端加密场景
前端加密通常用于以下几个场景:
- 登录密码加密传输
- API 参数签名
- 敏感信息传输
- 防止接口被直接调用
- Token 生成与验证
- 定位加密方法的技术
1. 断点调试法
最直接有效的方法是通过 Chrome DevTools 进行断点调试:
// 给常见加密函数设置断点
debug(CryptoJS.AES.encrypt); // 如果使用了 CryptoJS 库
debug(md5); // 如果使用了 MD5
debug(encodeURIComponent); // URL 编码
debug(btoa); // Base64 编码
操作步骤:
- 在可能的触发点(如表单提交、按钮点击)设置事件断点
- 在 Network 面板找到目标请求,查看加密参数
- 在网页中触发该操作,断点会在加密函数执行时停止
2. 函数重写拦截法
// 拦截常见加密函数
(function() {
// 保存原始函数
const originalMD5 = window.md5;
// 重写函数
window.md5 = function() {
console.log('MD5 调用参数:', arguments);
console.trace('MD5 调用堆栈');
return originalMD5.apply(this, arguments);
};
})();
这种方法可以应用于常见的加密库函数:
// 针对 CryptoJS
if (window.CryptoJS) {
const originalAES = CryptoJS.AES.encrypt;
CryptoJS.AES.encrypt = function() {
console.log('AES 加密参数:', arguments);
console.log('密钥:', arguments[1].toString());
return originalAES.apply(this, arguments);
};
}
3. 全局函数监控法
// 监控所有可能的加密函数
const potentialEncryptionFuncs = [
'encrypt', 'decrypt', 'encode', 'decode', 'hash',
'md5', 'sha1', 'sha256', 'aes', 'des', 'rsa'
];
function monitorFunctions(obj, path = '') {
if (!obj || typeof obj !== 'object') return;
Object.keys(obj).forEach(key => {
const currentPath = path ? `${path}.${key}` : key;
if (typeof obj[key] === 'function' &&
potentialEncryptionFuncs.some(funcName =>
key.toLowerCase().includes(funcName))) {
const original = obj[key];
obj[key] = function() {
console.log(`可能的加密函数被调用: ${currentPath}`, arguments);
return original.apply(this, arguments);
};
}
if (obj[key] && typeof obj[key] === 'object') {
monitorFunctions(obj[key], currentPath);
}
});
}
monitorFunctions(window);
4. 网络请求拦截法
// 拦截所有请求
const originalFetch = window.fetch;
window.fetch = async function() {
const url = arguments[0];
const options = arguments[1] || {};
console.log('Fetch 请求:', {
url,
method: options.method || 'GET',
headers: options.headers,
body: options.body
});
// 尝试解析请求体,寻找加密参数
if (options.body) {
try {
const bodyJson = JSON.parse(options.body);
Object.keys(bodyJson).forEach(key => {
if (typeof bodyJson[key] === 'string' && bodyJson[key].length > 20) {
console.log(`可能的加密参数: ${key}`, bodyJson[key]);
}
});
} catch (e) {}
}
return originalFetch.apply(this, arguments);
};
寻找密钥和盐的方法
1. 静态代码分析
查找特征字符串:
// 在控制台执行,搜索可能的密钥
(function findKeys() {
const htmlSource = document.documentElement.outerHTML;
// 常见密钥、盐的命名模式
const patterns = [
/['"]?(?:key|salt|secret|iv|token|nonce)['"]?\s*[:=]\s*['"]([^'"]{8,})['"]/,
/['"]?(?:aes|des|encryption|crypto)(?:Key|Salt|Iv)['"]?\s*[:=]\s*['"]([^'"]{8,})['"]/,
/const\s+(?:KEY|SALT|IV|SECRET)\s*=\s*['"]([^'"]{8,})['"]/
];
patterns.forEach(pattern => {
const matches = htmlSource.match(new RegExp(pattern, 'gi'));
if (matches) {
console.log('找到可能的密钥:', matches);
}
});
})();
2. 动态参数监控
// 监控加密函数的参数
function monitorEncryptionParams() {
const suspectFuncs = [
{obj: window.CryptoJS?.AES, method: 'encrypt'},
{obj: window.CryptoJS?.DES, method: 'encrypt'},
{obj: window, method: 'btoa'},
{obj: window, method: 'md5'},
// 添加其他可能的加密函数
];
suspectFuncs.forEach(({obj, method}) => {
if (obj && typeof obj[method] === 'function') {
const original = obj[method];
obj[method] = function() {
console.log(`${method} 调用:`, {
args: [...arguments],
possibleKey: arguments[1]?.toString?.() || arguments[1]
});
return original.apply(this, arguments);
};
}
});
}
monitorEncryptionParams();
3. 本地存储检查
// 检查localStorage和sessionStorage中的可能密钥
function checkStorageForKeys() {
const keyPatterns = [
/key/i, /salt/i, /secret/i, /token/i, /iv/i, /nonce/i, /sign/i, /crypto/i
];
console.log('检查 localStorage:');
Object.keys(localStorage).forEach(key => {
if (keyPatterns.some(pattern => pattern.test(key))) {
console.log(`可能的密钥 (localStorage): ${key} = ${localStorage.getItem(key)}`);
}
});
console.log('检查 sessionStorage:');
Object.keys(sessionStorage).forEach(key => {
if (keyPatterns.some(pattern => pattern.test(key))) {
console.log(`可能的密钥 (sessionStorage): ${key} = ${sessionStorage.getItem(key)}`);
}
});
}
checkStorageForKeys();
4. Cookie 检查
// 检查Cookie中的可能密钥
function checkCookiesForKeys() {
const keyPatterns = [
/key/i, /salt/i, /secret/i, /token/i, /iv/i, /nonce/i, /sign/i, /crypto/i
];
document.cookie.split(';').forEach(cookie => {
const [name, value] = cookie.trim().split('=');
if (keyPatterns.some(pattern => pattern.test(name))) {
console.log(`可能的密钥 (Cookie): ${name} = ${value}`);
}
});
}
checkCookiesForKeys();
常用工具
- Chrome DevTools - 断点调试、网络请求分析
- Fiddler/Charles - HTTP抓包分析
- JavaScript Deobfuscator - 反混淆加密代码
- Crypto Detective - 检测加密算法特征
- CyberChef - 在线加解密工具
案例分析
RSA加密定位案例
很多网站使用RSA对密码加密,可以通过以下方式定位:
// 监控 JSEncrypt 库
if (window.JSEncrypt) {
const originalEncrypt = window.JSEncrypt.prototype.encrypt;
window.JSEncrypt.prototype.encrypt = function(data) {
console.log('RSA 加密数据:', data);
console.log('RSA 公钥:', this.getPublicKey());
return originalEncrypt.call(this, data);
};
const originalSetPublicKey = window.JSEncrypt.prototype.setPublicKey;
window.JSEncrypt.prototype.setPublicKey = function(key) {
console.log('设置 RSA 公钥:', key);
return originalSetPublicKey.call(this, key);
};
}
AES加密定位案例
// 监控 CryptoJS AES
if (window.CryptoJS && window.CryptoJS.AES) {
const originalEncrypt = window.CryptoJS.AES.encrypt;
window.CryptoJS.AES.encrypt = function(message, key, cfg) {
console.log('AES 加密信息:', {
原文: message.toString(),
密钥: key.toString(),
配置: cfg
});
return originalEncrypt.apply(this, arguments);
};
}
防御措施
作为开发者,如何避免前端加密被轻易破解:
- 不要只依赖前端加密 - 始终在服务器端进行密码验证
- 使用HTTPS - 加密传输所有数据
- 混淆和代码保护 - 增加逆向难度
- 动态密钥 - 每次请求使用不同的密钥
- 服务器验证 - 关键业务逻辑放在服务器端
💬 评论