能否使用WebAssembly验证其所调用JavaScript方法的完整性?
验证WebAssembly调用的JavaScript方法完整性方案
针对你提到的场景——WASM模块不可篡改,但JavaScript侧存在被篡改风险,要验证WASM调用的validateMe方法完整性,这里有几个实用的方案,结合你的C代码示例展开说明:
方案1:基于函数源码哈希验证
核心思路是:在不可篡改的WASM中预存validateMe的正确源码哈希,然后让WASM获取当前环境中validateMe的源码,计算哈希后与预存值对比。
修改后的C代码示例
#include <emscripten.h> #include <string.h> #include <stdio.h> // 预存的validateMe函数正确SHA-256哈希(替换成你实际计算的哈希值) const char* EXPECTED_VALIDATEME_HASH = "a1b2c3d4e5f6..."; // 从JS侧获取validateMe的源码(同时防范Function.prototype.toString被篡改) EM_JS(const char*, get_validateme_source, (), { // 先保存原始的Function.toString方法,避免被篡改的toString返回假源码 const originalToString = Function.prototype.toString; // 调用原始方法获取validateMe的真实源码 return originalToString.call(validateMe); }); // 简易SHA-256计算实现(你可以引入成熟的哈希库,比如mbedtls) void sha256(const unsigned char* data, size_t len, unsigned char* hash) { // 这里省略具体实现,建议使用经过安全审计的哈希库 // 示例仅做占位,实际开发请替换为可靠实现 } int validateMethods(){ // 获取validateMe的源码 const char* source = get_validateme_source(); if (!source || strlen(source) == 0) { emscripten_console_log("Failed to get validateMe source"); return 0; } // 计算源码的SHA-256哈希 unsigned char raw_hash[32]; sha256((const unsigned char*)source, strlen(source), raw_hash); // 将二进制哈希转为十六进制字符串 char computed_hash[65] = {0}; for (int i = 0; i < 32; i++) { sprintf(&computed_hash[i*2], "%02x", raw_hash[i]); } // 对比预存哈希 if (strcmp(computed_hash, EXPECTED_VALIDATEME_HASH) != 0) { emscripten_console_log("validateMe source has been tampered!"); return 0; } return 1; } EMSCRIPTEN_KEEPALIVE void doSomething() { if (validateMethods()) { validateMe(); // 验证通过,执行核心逻辑 } else { // 验证失败,终止操作 emscripten_console_log("Aborted: Invalid validateMe method"); } }
方案优缺点
- ✅ 优点:直接验证函数源码完整性,只要哈希匹配,就能确保源码未被篡改。
- ❌ 缺点:依赖
Function.prototype.toString的真实性,如果攻击者篡改了这个方法返回假源码,会绕过验证。可以额外增加对toString方法的哈希验证,进一步提升安全性。
方案2:基于函数行为的白盒验证
如果源码哈希验证存在被绕过的风险(比如攻击者篡改源码但保持行为一致),可以通过测试函数输入输出的预期行为来验证完整性。
修改后的C代码示例
#include <emscripten.h> #include <string.h> // 调用validateMe并返回整数结果(针对有返回值的场景) EM_JS(int, test_validateme_int, (int input), { return validateMe(input); }); // 调用validateMe并返回字符串结果 EM_JS(const char*, test_validateme_str, (const char* input), { return validateMe(UTF8ToString(input)); }); int validateMethods(){ // 测试1:整数输入输出是否符合预期 if (test_validateme_int(100) != 200) { emscripten_console_log("validateMe failed integer test"); return 0; } // 测试2:字符串输入输出是否符合预期 const char* str_result = test_validateme_str("hello_wasm"); if (!str_result || strcmp(str_result, "HELLO_WASM") != 0) { emscripten_console_log("validateMe failed string test"); return 0; } // 可以添加更多边缘场景测试 return 1; } EMSCRIPTEN_KEEPALIVE void doSomething() { if (validateMethods()) { validateMe(); // 执行后续逻辑 } else { emscripten_console_log("Aborted: validateMe behavior is invalid"); } }
方案优缺点
- ✅ 优点:不依赖源码,只关注函数实际行为,即使源码被修改但功能未变,也不影响业务;能检测恶意篡改行为。
- ❌ 缺点:如果
validateMe是无参数无返回值的函数,需要调整函数逻辑增加测试入口;测试用例覆盖不全时,可能漏掉部分篡改场景。
方案3:双重验证(源码哈希+行为测试)
为了最大化安全性,建议结合前两种方案:先验证源码哈希确保未被篡改,再通过行为测试确认功能正常。这种组合能应对大多数篡改场景,提升验证的可靠性。
关键注意事项
- 哈希预存:确保预存的哈希值是
validateMe源码的真实哈希,编译WASM前提前计算并硬编码到C代码中。 - 哈希算法选择:使用SHA-256、SHA-3等安全哈希算法,避免使用MD5、SHA-1等已被破解的算法。
- 防范JS环境篡改:对于依赖的JS内置方法(如
Function.prototype.toString),可以额外添加验证步骤,确保这些方法未被篡改。
内容的提问来源于stack exchange,提问作者Shlomi Schwartz
相关产品推荐
相关产品推荐

