从明码 CSV 到 AES 加密 TXT:Cocos3.8 游戏数据加密实践

在小游戏开发过程中,数据存储是绕不开的环节。做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实现了这个加密小工具示例,最终未作混淆实现,如果追求安全性可以自行实现。另外各位有没有二进制加密比较好的方案,可以在评论区指点一下。

相关推荐
CodeCaptain1 天前
CocosCreator3.8.x 解析Tiled1.4.x【瓦片图层、对象图层、图像图层、组图层】的核心原理
经验分享·游戏·typescript·cocos2d
CodeCaptain4 天前
Cocos Creator 3.8.0 官方文档明确支持 Tiled Editor v1.4 版本,也兼容 1.4.x 小版本(如1.4.3)
cocos2d
怣疯knight4 天前
cocos creator 的几个变量显示写法
cocos2d
CodeCaptain4 天前
Cocos Creator3.8.0 Tiled地图三合一完整脚本(加载+兼容性校验+坐标互转,一键可用,适配Tiled1.4.x)
游戏·cocos2d
CodeCaptain4 天前
一个快速校验地图资源是否符合兼容要求的小脚本(Cocos Creator3.8.0)
游戏·typescript·cocos2d
CodeCaptain4 天前
Cocos Creator3.8.0 + Tiled1.4.x 地图加载FAQ(高频报错+秒解)
cocos2d
芳草萋萋鹦鹉洲哦8 天前
【pixijs】关于pixijs画圆
cocos2d·js
怣疯knight10 天前
Cocos creator避坑指南(一些比较容易错的地方)
cocos2d
jumu20217 天前
COMSOL凝固模拟:从溶质偏析到枝晶生长实战
cocos2d