How to protect your JS code by WebAssembly

2021-01-22 22:25:51

参考地址  How to protect your JS code by WebAssembly

基本概念

一、代码安全

Ref: 前端核心代码保护技术面面观

 对于iOS或是Android来说,我们可以将相关的算法通过C/C++进行编写,然后编译为dylib或是so并进行混淆以此来增加破解的复杂度,但是对于前端来说,并没有类似的技术可以使用。当然,自从asm.js及WebAssembly的全面推进后,我们可以使用其进一步增强我们核心代码的安全性,但由于asm.js以及WebAssembly标准的开放,其安全强度也并非想象中的那么美好。

 

  • 使用Javascript的混淆器

对于Javascript的混淆器我们是不陌生的,我们常常使用其进行代码的压缩以及混淆以此来减少代码体积并增加人为阅读代码的复杂度。

 

  • 使用Flash的C/C++扩展方式

在Flash还大行其道的时期,为了更好的方便引擎开发者使用C/C++来提升Flash游戏相关引擎的性能,Adobe开源了 CrossBridge 这个技术。在这种过程中,原有的C/C++代码经过LLVM IR变为Flash运行时所需要的目标代码,不管是从效率提升上还是从安全性上都有了非常大的提升。对于目前的开源的反编译器来说,很难反编译由CorssBridge编译的C/C++代码,并且由于Flash运行时生产环境中禁用调试,因此也很难进行对应的单步调试。 

 

  • 使用asm.js或WebAssembly

目前看起来WebAssembly是目前最理想的前端核心代码保护的方案了,我们可以使用C/C++编写相关的代码,使用Emscripten相关工具链编译为asm.js和wasm,根据不同的浏览器的支持情况选择使用asm.js还是wasm。并且对于PC端IE10以下的浏览器,我们还可以通过CrossBridge复用其C/C++代码,产出对应的Flash目标代码,从而达到非常好的浏览器兼容性。

然而使用asm.js/wasm后对于前端核心代码的保护就可以高枕无忧了么?

由于asm.js以及wasm的标准规范都是完全公开的,因此对于asm.js/wasm标准实现良好反编译器来说,完全可以尽可能的产出阅读性较强的代码从而分析出其中的核心算法代码。但幸运的是,目前作者还暂时没有找到实现良好的asm.js/wasm反编译器,因此我暂时认为使用此种方法在保护前端核心代码的安全性上已经可堪重用了。

复制代码

#include <string>#include <emscripten.h>#include <emscripten/bind.h>#include "md5.h"#define SALTKEY "md5 salt key"std::string sign(std::string str){    return md5(str + string(SALTKEY));
}// 此处导出sign方法供Javascript外部环境使用EMSCRIPTEN_BIND(my_module){
    emscripten::function("sign", &sign);
}

复制代码

Compile and export js.

em++ -std=c++11 -Oz --bind \    -I ./md5 ./md5/md5.cpp ./sign.cpp \    -o ./sign.js

复制代码

<body>
    <script src="./sign.js"></script>
    <script>        // output: 0b57e921e8f28593d1c8290abed09ab2
        Module.sign("This is a test string");    </script>
</body>

复制代码

 

  • SecurityWorker - 更好的思路及其实现

/* 作者自己的策略,详见原链接 */

 

Ref: 发现比起混淆, emscripten 或 webassenbly 才是保护代码的好办法

开发者在遇到较大代码量时,可以考虑上 emscripten 或者 webassenbly 来保护自己的代码。
虽说前端没有破不了的防护,但这两样东西真的是靠很简单的方法就能达到相当好的保护目的能。而且尤其是当你代码混淆+这些之后,对攻击者来说,那酸爽,简直了。

 

二、概念理解

Ref: Javascript支持3D游戏,asm.js 和 Emscripten工具,以及和WebAssembly的区别

2012年,Mozilla 的工程师 Alon Zakai 在研究 LLVM 编译器时突发奇想:许多 3D 游戏都是用 C / C++ 语言写的,如果能将 C / C++ 语言编译成 JavaScript 代码,它们不就能在浏览器里运行了吗?众所周知,JavaScript 的基本语法与 C 语言高度相似。为此专门做了一个编译器项目 Emscripten。这个编译器可以将 C / C++ 代码编译成 JS 代码,但不是普通的 JS,而是一种叫做 asm.js 的 JavaScript 变体

 

  • asm.js 与 WebAssembly 的异同

还有一种叫做 WebAssembly 的技术。两者的功能基本一致,就是转出来的代码不一样:asm.js 是文本,WebAssembly 是二进制字节码,因此运行速度更快、体积更小。

但是,这并不意味着 asm.js 肯定会被淘汰,因为它有两个优点:首先,它是文本,人类可读,比较直观;其次,所有浏览器都支持 asm.js,不会有兼容性问题。 

 

  • 编译执行流程

Emscripten 的底层是 LLVM 编译器,理论上任何可以生成 LLVM IR(Intermediate Representation)的语言,都可以编译生成 asm.js。 但是实际上,Emscripten 几乎只用于将 C / C++ 代码编译生成 asm.js。

C/C++ ⇒ LLVM ==> LLVM IR ⇒ Emscripten ⇒ asm.js

 

三、新书资源

我的新书《深入浅出WebAssembly》出版啦(。・ω・。)ノ [有点意思]

  • 未来技术变革

https://myslide.cn/slides/21201#

mxnet也是一个不错的选择。

 

 

安装配置

一、Developer’s Guide

https://webassembly.org/getting-started/developers-guide/

https://www.wasm.com.cn/getting-started/developers-guide/

 

二、安装

想要编译成WebAssembly,你首先需要先编译 LLVM。

 

  • 安装LLVM

Ref: LLVM概述——介绍与安装

Goto: https://releases.llvm.org/

选择本地编译安装。

 

  • 安装emcc

How to install the latest emscripten on Ubuntu using command line?

复制代码

From the emscripten/. Make the  SDK //

复制代码

 

这里报错如下,但先不管,上述步骤后,已经可以使用emcc命令。

$ ./emsdk install sdk-incoming-64bit binaryen-master-64bit
Error: No tool or SDK found by name 'sdk-incoming-64bit'.

  

三、测试环境

  • C语言

下面这些命令可能让你创建一个简单的“hello word”程序,并且编译它。

复制代码

$ mkdir hello
$ cd hello
$ echo '#include <stdio.h>' > hello.c
$ echo 'int main(int argc, char ** argv) {' >> hello.c
$ echo 'printf("Hello, world!\n");' >> hello.c
$ echo '}' >> hello.c
$ emcc hello.c -s WASM=1 -o hello.html

复制代码

我们可以使用 emrun 命令来创建一个 http 协议的 web server 来展示我们编译后的文件。

$ emrun --no_browser --port 8080 .

HTTP 服务开启后,您可以在浏览器中打开。如果你看到了“Hello,word!”输出到了 Emscripten 的 控制面板,恭喜你!你的 WebAssembly 程序编译成功了!

 

  • C++语言

要先执行自动环境变量配置,或者直接手动在 ~/.bashrc 中设置也可。

复制代码

$ emsdk_env.sh --build=Release
Adding directories to PATH:
PATH += /usr/local/emsdk/upstream/emscripten
PATH += /usr/local/emsdk/node/12.9.1_64bit/bin

Setting environment variables:
EMSDK = /usr/local/emsdk
EM_CONFIG = /home/jeffrey/.emscripten
EM_CACHE = /usr/local/emsdk/upstream/emscripten/cache
EMSDK_NODE = /usr/local/emsdk/node/12.9.1_64bit/bin/node

复制代码

步骤与上一条的C语言操作类似。

em++ hello.cpp -s WASM=1 -o hello.html

$ ls
hello.cpp hello.html hello.js hello.wasm

emrun --no_browser --port 8080 .

 

 

原理剖析

一、基本JS解析步骤

Ref: 几张图让你看懂WebAssembly 

Parsing讲源码转换成解释器可以运行的东西所用的事情。
Compiling + optimizing花费在基础编译和优化编译上的时间。有一些优化编译的工作不在主线程,所以这里并不包括这些时间。
Re-optimizing当预先编译优化的代码不能被优化的情况下,JIT 将这些代码重新优化,如果不能重新优化那么久丢给基础编译去做。这个过程叫做重新优化。
Execution执行代码的过程
Garbage collection清理内存的时间

 

一个重要的事情要注意:这些任务不会发生在离散块或特定的序列中。相反,它们将被交叉执行。

比如正在做一些代码解析时,还执行者一些其他的逻辑,有些代码编译完成后,引擎又做了一些解析,然后又执行了一些逻辑,等等。

 

WebAssembly 和别的汇编语言是有一些不同的。所以他是一个概念机上的机器语言,不是在一个真正存在的物理机上运行的机器语言。

正因如此,WebAssembly 指令有时候被称为虚拟指令。它比 JavaScript 代码更快更直接的转换成机器代码,但它们不直接和特定硬件的特定机器代码对应。

在浏览器下载 WebAssembly后,使 WebAssembly 的迅速转换成目标机器的汇编代码。

 


  • 2019-12-10 11:15:08

    用CSS给SVG 的内容添加样式

    SVG图形的一个最常见用例是图标系统,其中最常用的SVG sprite技术就是使用SVG<use> 元素在文档中任意位置“实例化”图标。 使用<use>元素实例化图标或任何其它的SVG元素或图像,给元素添加样式时经常会碰到一些问题。这篇文章的目的是尽可能给你介绍一些方法来解决:使用<use>引入的内容添加样式受限的问题。 但是在开始之前,我们先快速浏览一下SVG的主要结构和分组元素,然后慢慢进入use的世界中,以及shadow DOM,然后重回CSS的怀抱。我们会逐步讲解为什么给<use>内容添加样式会比较麻烦,以及有什么好的解决方案。

  • 2019-12-10 16:21:05

    display:flex的子元素无法设置宽度

    子元素有个flex-shrink属性,表示在父元素宽度不够的情况下是自动收缩不?0表示不自动收缩,1表示自动收缩;所以将子元素(图片)添加属性:flex-shrink:0;即

  • 2019-12-10 21:14:11

    axios文件上传功能+formData

    在项目中使用axios上传文件,记得new一个纯净的axios或者考虑用ajax请求。因为axios在项目估计已经用了全局配置请求头等信息,这里的配置可能被全局请求头拦截,导致请求失败。 2.1构造formData 作者:exmexm 链接:https://www.jianshu.com/p/9c708a47d8a5 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 2019-12-11 16:04:15

    CSS中的 “var()” 和 “:root”

    var() var()函数可以代替元素中任何属性中的值的任何部分。var()函数不能作为属性名、选择器或者其他除了属性值之外的值。(这样做通常会产生无效的语法或者一个没有关联到变量的值。)

  • 2019-12-11 16:18:51

    npm发布vue组件

    开发之前先看看官网的 开发规范 我们开发的之后期望的结果是支持 import、require 或者直接使用 script 标签的形式引入,就像这样

  • 2019-12-11 16:21:00

    .vue文件 加scoped 样式不起作用

    在vue组件中,为了使样式私有化(模块化),不对全局造成污染,在style标签上添加scoped属性,以表示它只属于当下的模块。但是要慎用,因为在我们需要修改公共组件(第三方库或者项目中定制的组件)的样式的时候,scoped会造成很多困难,组要增加额外的复杂度。

  • 2019-12-11 16:22:04

    Vue中的scoped和scoped穿透,scoped原理

    在Vue文件中的style标签上有一个特殊的属性,scoped。当一个style标签拥有scoped属性时候,它的css样式只能用于当前的Vue组件,可以使组件的样式不相互污染。如果一个项目的所有style标签都加上了scoped属性,相当于实现了样式的模块化。