在小游戏开发过程中,数据存储是绕不开的环节。做demo的初期为了快速迭代,我直接采用明码 CSV 文件存储游戏配置(比如关卡数据、道具属性、角色数值),虽然开发效率高,但明码数据的安全性问题显而易见 —— 玩家可轻易修改文件篡改游戏数据,破坏游戏平衡。本想通过二进制文件存储提升安全性,但是我在 Cocos3.8 读取二进制文件需要非常绕圈子的配置,因为缓存需要不断的重启相当烦恼,最终不搞纯二进制而是选择了加密后保存为 TXT 文件的方案,本文就聊聊这个过程中的踩坑与解决方案。

winform 版本地址

https://gitee.com/wgc2k/csv_encrypter

一、初期痛点:明码 CSV 的安全隐患

小游戏开发初期,CSV 因 “易编辑、易解析” 成为我的首选:用 Excel 整理数据,导出为 CSV 后,Cocos 通过简单的文件读取和字符串分割就能解析。但上线前的安全自测让我发现问题:玩家只需用记事本打开 CSV 文件,就能随意修改关卡奖励、道具数量等核心数据,甚至能直接解锁所有关卡。

举个简单的 CSV 示例(game_config.csv):

level,gold,reward
1,100,coin_10
2,200,coin_20
3,300,diamond_5

这种明码存储方式对小游戏而言,虽不至于引发严重安全事故,但会彻底破坏游戏体验,数据加密势在必行。

二、踩坑:Cocos3.8 读取二进制文件的 “水土不服”

最初的优化思路是将 CSV 转为二进制文件(比如自定义格式的 bin 文件),二进制文件本身具备一定的 “隐蔽性”,且读取效率更高。但在 Cocos3.8 中实现时,却遇到了一系列问题:

1. 二进制文件读取的核心问题

Cocos3.8 基于 TypeScript/JavaScript 开发,其文件读取 API(cc.assetManager.loadAnyfs.readFile)对文本文件的支持非常友好,但处理二进制文件时存在明显短板:

  • 跨平台兼容性差:在 Web 端、微信小游戏端、原生端读取二进制文件时,数据解析格式不一致(比如 Uint8Array 和 ArrayBuffer 的转换差异);
  • 解析成本高:自定义二进制格式需要编写复杂的序列化 / 反序列化逻辑,对小游戏轻量化开发而言过于繁琐;
  • 缓存机制干扰:Cocos 的资源缓存会对二进制文件做额外处理,调试时候会出现读取到旧数据的情况。

2. 尝试后的放弃

我曾编写过简单的二进制文件读写工具,将 CSV 数据转为二进制流存储,但在多端测试时,Web 端能正常读取,微信小游戏端却出现数据截断,原生端有时报文件解析错误。反复调试后发现,Cocos3.8 对不同平台的二进制文件编码、字节序处理存在未统一的细节,修复成本远超预期,最终决定放弃纯二进制方案。

三、折衷方案:AES 加密 + TXT 文件存储

既然二进制方案落地困难,我转向 “文本文件 + 加密” 的思路:用 AES 对称加密算法对 CSV 数据加密,将加密后的密文保存为 TXT 文件,游戏运行时读取 TXT 密文,解密后再解析为可用数据。这个方案兼顾了安全性和开发效率,且 Cocos3.8 对 TXT 文件的读取支持完善。

1. 核心思路

  1. 开发离线工具:将 Excel/CSV 中的明码数据,通过 AES 加密生成密文;
  2. 密文存储:将加密后的密文保存为 TXT 文件,放入 Cocos 资源目录;
  3. 游戏内解密:运行时读取 TXT 密文,通过 AES 解密得到原始 CSV 数据,再解析使用。

2. 实现代码(Node.js 离线加密工具 + Cocos3.8 解密逻辑)

第一步:Node.js 离线加密工具(处理 CSV 生成加密 TXT)

先通过 Node.js 编写加密脚本,将明码 CSV 转为加密 TXT(需安装crypto-js依赖):

bash运行

npm install crypto-js --save

javascript

// encrypt-csv.js
const CryptoJS = require('crypto-js');
const fs = require('fs');
const path = require('path');

// 配置AES密钥(建议16/24/32位,对应AES-128/AES-192/AES-256)
const AES_KEY = CryptoJS.enc.Utf8.parse('1234567890abcdef'); // 16位密钥
const AES_IV = CryptoJS.enc.Utf8.parse('abcdef1234567890');  // 16位偏移量

/**
 * AES加密函数(CBC模式,PKCS7填充)
 * @param {string} plainText 明文(CSV文本)
 * @returns {string} 加密后的密文
 */
function aesEncrypt(plainText) {
    const encrypted = CryptoJS.AES.encrypt(
        plainText,
        AES_KEY,
        {
            iv: AES_IV,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }
    );
    return encrypted.toString();
}

// 读取CSV明码文件
const csvPath = path.join(__dirname, 'game_config.csv');
const txtOutputPath = path.join(__dirname, 'game_config_encrypt.txt');

fs.readFile(csvPath, 'utf8', (err, data) => {
    if (err) {
        console.error('读取CSV失败:', err);
        return;
    }
    // 加密CSV数据
    const cipherText = aesEncrypt(data);
    // 保存为TXT文件
    fs.writeFile(txtOutputPath, cipherText, 'utf8', (err) => {
        if (err) {
            console.error('保存加密TXT失败:', err);
            return;
        }
        console.log(`加密完成!密文已保存至:${txtOutputPath}`);
    });
});

运行脚本生成加密 TXT:

bash

node encrypt-csv.js
第二步:Cocos3.8 中解密并解析 TXT

在 Cocos3.8 项目中,先引入crypto-js(可通过 npm 安装后拷贝到项目,或直接引入 CDN 版本),然后编写解密逻辑:

typescript

// GameDataManager.ts
import { _decorator, Component, Node, assetManager, resources } from 'cc';
const { ccclass, property } = _decorator;

// 引入crypto-js(需将crypto-js的包放入项目,或通过import映射)
import CryptoJS from './crypto-js.min';

// 与加密端一致的密钥和偏移量
const AES_KEY = CryptoJS.enc.Utf8.parse('1234567890abcdef');
const AES_IV = CryptoJS.enc.Utf8.parse('abcdef1234567890');

/**
 * AES解密函数
 * @param {string} cipherText 密文
 * @returns {string} 解密后的明文
 */
function aesDecrypt(cipherText: string): string {
    const decrypt = CryptoJS.AES.decrypt(
        cipherText,
        AES_KEY,
        {
            iv: AES_IV,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }
    );
    return CryptoJS.enc.Utf8.stringify(decrypt).toString();
}

@ccclass('GameDataManager')
export class GameDataManager extends Component {
    // 游戏配置数据
    private gameConfig: any[] = [];

    onLoad() {
        this.loadAndDecryptData();
    }

    /**
     * 加载加密TXT并解密解析
     */
    private async loadAndDecryptData() {
        try {
            // 读取加密TXT文件(放入resources目录)
            const res = await resources.loadAsync('game_config_encrypt', { type: cc.TextAsset });
            const cipherText = res.text;
            
            // 解密得到CSV明文
            const csvPlainText = aesDecrypt(cipherText);
            
            // 解析CSV数据(简单分割,复杂场景可引入csv-parser)
            this.parseCsv(csvPlainText);
            
            console.log('数据解密解析完成:', this.gameConfig);
        } catch (err) {
            console.error('数据加载解密失败:', err);
        }
    }

    /**
     * 解析CSV明文为数组
     * @param {string} csvText CSV明文
     */
    private parseCsv(csvText: string) {
        const lines = csvText.split('\n').filter(line => line.trim());
        const headers = lines[0].split(',');
        
        for (let i = 1; i < lines.length; i++) {
            const values = lines[i].split(',');
            const row: any = {};
            headers.forEach((header, index) => {
                row[header] = values[index];
            });
            this.gameConfig.push(row);
        }
    }
}

3. 关键注意事项

  1. 密钥安全:AES 密钥和偏移量不要直接写在代码里!可通过混淆、分段拼接等方式隐藏,避免反编译后被提取;
  2. 跨平台适配:Cocos3.8 的resources.loadAsync读取 TXT 在各端表现一致,无需额外适配;
  3. 性能优化:解密操作建议在游戏启动时执行一次,将解析后的数据缓存,避免重复解密;
  4. 加密模式:选择 CBC 模式(需偏移量 IV)而非 ECB 模式,ECB 模式安全性较低,易被破解。

四、方案对比与效果

存储方式安全性开发成本跨平台兼容性读取效率
明码 CSV极低极低极好较高
自定义二进制中等极高较差最高
AES 加密 TXT较高中等极好中等

实际测试中,AES 加密 TXT 方案在 Web、微信小游戏、原生端均能稳定运行,解密耗时在毫秒级,对小游戏性能几乎无影响;同时,玩家即使找到 TXT 文件,也无法直接修改密文(AES 加密无密钥无法破解),有效解决了数据篡改问题。

五、进阶优化方向思路

  1. 数据压缩:加密前先对 CSV 数据进行 GZIP 压缩,减少 TXT 文件体积;
  2. 密钥动态生成:通过服务器下发密钥(小游戏首次启动时请求),彻底避免本地密钥泄露;
  3. 混合加密:对核心数据(如玩家等级、金币)采用 “非对称加密 + 对称加密” 混合方案,进一步提升安全性;
  4. 数据校验:解密后增加 MD5 校验,防止密文被篡改后解密失败导致游戏崩溃。

总结

在 Cocos3.8 小型游戏开发中,数据加密不必追求 “纯二进制” 的极致方案,结合自身开发成本和跨平台需求,选择 “AES 加密 + TXT 存储” 的折衷方案是更务实的选择。这个方案既解决了明码 CSV 的安全隐患,又避开了 Cocos3.8 读取二进制文件的兼容性问题,兼顾了安全性、开发效率和跨平台适配性。我最终使用了winform实现了这个加密小工具示例,最终未作混淆实现,如果追求安全性可以自行实现。另外各位有没有二进制加密比较好的方案,可以在评论区指点一下。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐