You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cordova Vue加密钱包助记词Salt安全实现代码审计请求

安全审查与优化建议

现有实现的核心问题

1. 硬编码全局盐严重削弱安全性

当前代码中const salt是固定硬编码值,所有用户共用同一个盐。盐的核心作用是防止彩虹表攻击,固定盐会让攻击者针对性生成彩虹表,一旦泄露,所有用户的加密数据都面临被破解风险,完全失去盐的安全价值。

2. 加密函数参数错误,密码未实际参与加密

createKey中调用encryptMnemonic(seedPhrase, pincode, password),但encryptMnemonic仅定义了两个参数,第三个参数password被直接忽略,实际加密仅使用pincode + salt作为密钥。这意味着用户设置的密码完全没起到加密作用,PIN码本身通常是短数字,极易被暴力破解。

3. 未使用密钥派生函数(KDF),密钥强度不足

直接将PIN/密码与盐拼接作为AES密钥,没有经过PBKDF2、Argon2等专业KDF处理。这类函数通过多次迭代计算,能大幅提升暴力破解成本,尤其是针对PIN这类短输入,KDF是必不可少的安全环节。

4. AES加密未使用随机IV,存在重复密文风险

CryptoJS的AES.encrypt默认使用CBC模式,但如果不指定随机IV,相同的明文+密钥会生成完全相同的密文。攻击者可通过密文重复推断明文信息,甚至实施重放攻击。

5. 明文返回助记词,加密完全失效

createKey的返回值中包含seed: seedPhrase,直接暴露明文助记词。无论加密逻辑多么完善,只要明文助记词泄露,钱包安全性就彻底丧失。

6. 以太坊地址未做校验和处理

当前生成的以太坊地址是纯小写格式,不符合以太坊校验和规范,用户后续使用中容易因输入错误导致资产损失。

针对性优化方案

1. 为每个用户生成独立随机盐

删除硬编码全局盐,创建钱包时生成16字节以上的随机盐,并将盐与加密后的助记词一起存储(盐无需保密,只需唯一)。示例:

// 生成随机盐
const generateSalt = () => CryptoJS.lib.WordArray.random(128/8).toString();

2. 修复加密逻辑,让PIN+密码共同参与加密

修改encryptMnemonic函数,接收PIN和密码,组合后通过KDF生成密钥:

function encryptMnemonic(mnemonic, pincode, password, salt) {
    // 组合PIN与密码,避免单一因素泄露风险
    const combinedInput = `${pincode}:${password}`;
    // 使用PBKDF2派生密钥,迭代次数建议10万次以上
    const key = CryptoJS.PBKDF2(combinedInput, salt, {
        keySize: 256/32,
        iterations: 100000,
        hasher: CryptoJS.algo.SHA256
    });
    // 生成随机IV
    const iv = CryptoJS.lib.WordArray.random(128/8);
    // 执行AES加密
    const encrypted = CryptoJS.AES.encrypt(mnemonic, key, { iv: iv });
    // 返回密文、IV、盐(三者缺一不可解密)
    return {
        ciphertext: encrypted.ciphertext.toString(),
        iv: iv.toString(),
        salt: salt
    };
}

3. 完善解密逻辑并验证结果

解密时恢复明文后,需验证助记词有效性,避免无效数据导致后续错误:

function decryptMnemonic(ciphertext, iv, salt, pincode, password) {
    const combinedInput = `${pincode}:${password}`;
    const key = CryptoJS.PBKDF2(combinedInput, salt, {
        keySize: 256/32,
        iterations: 100000,
        hasher: CryptoJS.algo.SHA256
    });
    const decryptedBytes = CryptoJS.AES.decrypt(
        { ciphertext: CryptoJS.enc.Hex.parse(ciphertext) },
        key,
        { iv: CryptoJS.enc.Hex.parse(iv) }
    );
    const mnemonic = decryptedBytes.toString(CryptoJS.enc.Utf8);
    // 验证助记词有效性
    if (!bip39.validateMnemonic(mnemonic)) {
        throw new Error("解密失败,助记词无效");
    }
    return mnemonic;
}

4. 删除明文助记词的返回

修改createKey的返回值,移除seed: seedPhrase,绝对不能在任何环节暴露明文助记词:

return {
  success: true,
  key: encrypted, // 存储包含密文、IV、盐的对象
  btc: address,
  eth: ethAddress
}

5. 优化以太坊地址生成

将生成的以太坊地址转换为校验和格式:

const ethAddress = ethUtil.toChecksumAddress(hexlify(tvt));

6. 升级依赖库版本

当前使用的ethers v5.5.4版本较旧,存在潜在安全漏洞,建议升级到最新稳定版(如v6.x),同时确保bip39、bitcoinjs-lib等其他依赖为最新安全版本。

7. 离线存储的适配

将加密后的助记词、IV、盐一起存储在本地(如localStorage或IndexedDB),确保离线状态下可正常读取并解密,无需依赖后端服务。

内容的提问来源于stack exchange,提问作者Eugeny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:20:14