Рекомендуется собирать и использовать WebAssembly для защиты основного кода фронтенда JS.

внешний интерфейс JavaScript
Рекомендуется собирать и использовать WebAssembly для защиты основного кода фронтенда JS.

предисловие

я провел в прошлом месяце2天разработал совершенно новыйVSCode插件Называется "Я люблю Наггетс", чтобы все землекопы могли превратиться в головастиков, в VSCode实时聊天. используя проект с открытым исходным кодомworkerman-todpole, я сделал много модификаций и оптимизаций на основе исходного проекта. Я также попытался добавить некоторые функции управления домом, например, только администратор может использовать большой красный свет, только администратор может загораться и так далее.

Но праведные землекопы вскоре начали пробовать различные методы, чтобы сломать это [неравное] обращение, среди которых@Этот котенок красавчикСтуденты также разработали различныеПрудовый робот, который может играть NPC в пруду, чтобы помочь начинающим пользователям. Теперь идею с большими глазами у головастика тоже предлагает тот самый кот Сяошуай, одноклассник, это действительно здорово💯.

необходимость

Чтобы реализовать функцию управления домом, мне нужно реализовать метод для создания и активации расширенных команд, и после активации я смогу получить расширенные разрешения. Очевидно, я не хочу, чтобы кто-нибудь видел, как я генерирую и проверяю команды в этом коде.

Я также не хочу ставить его на сервер, чтобы сделать бэкенд-интерфейс, потому что каждый раз запрашивать интерфейс будет давить на сервер. И websocket должен проверять эту расширенную команду каждый раз, когда он получает сообщение.

Итак, я определил два основных требования

  • Генерация и активация расширенных команд выполняется непосредственно во внешнем интерфейсе, минуя запросы к серверу.
  • Основная логика генерации и активации не может быть видна, иначе она потеряет смысл.

После некоторых исследований было обнаруженоWebAssemblyЭто может удовлетворить мои две потребности, и следующим шагом будет настоящий бой.

Введение в веб-сборку

WebAssembly обладает полным набором семантики и может генерировать двоичный формат .wasm, который имеет небольшой размер и быструю загрузку.Его цель состоит в том, чтобы полностью использовать возможности оборудования для достижения собственной эффективности выполнения.

по-прежнему работает в браузере, но использует двоичный формат.wasmдокумент, что полностью соответствует моим потребностям, а основные браузеры имеют хорошую совместимость с WebAssembly.

Например, следующий код можно скопировать и вставить в окно отладки браузера, чтобы испытать

WebAssembly.compile(new Uint8Array(`
  00 61 73 6d  01 00 00 00  01 0c 02 60  02 7f 7f 01
  7f 60 01 7f  01 7f 03 03  02 00 01 07  10 02 03 61
  64 64 00 00  06 73 71 75  61 72 65 00  01 0a 13 02
  08 00 20 00  20 01 6a 0f  0b 08 00 20  00 20 00 6c
  0f 0b`.trim().split(/[\s\r\n]+/g).map(str => parseInt(str, 16))
)).then(module => {
  const instance = new WebAssembly.Instance(module)
  const { add, square } = instance.exports

  console.log('2 + 4 =', add(2, 4))
  console.log('3^2 =', square(3))
  console.log('(2 + 5)^2 =', square(add(2 + 5)))

})

Очевидно, вы не можете легко знать, чтоUint8ArrayКак реализован алгоритм в...

Но писать код и компилировать в.wasmДокумент не слишком простой, например, в данном случае я выбираюC++написать код и передатьemscriptenЦепочка инструментов компилируется в.wasmдокумент.

emscripten

Установитьemscriptenокрестности

# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory
cd emsdk

# Fetch the latest version of the emsdk (not needed the first time you clone)
git pull

# Download and install the latest SDK tools.
./emsdk install latest

# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./emsdk activate latest

# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh

Официальная документация WebAssembly

После установки окружения сразу напишем абзацC语言, и компилируется в.wasmПусть работает в браузере.

#include <stdio.h>

int main(int argc, char ** argv) {
    printf("掘友们好");
    printf("\n");
    printf("这是一段来自C语言的问候");
    printf("\n");
}

команда компиляции

emcc helloworld.c -s WASM=1 -o helloworld.html

После компиляции не забудьте запустить службу, напримерlive-server, так как нам нужно прочитать локальный.wasmдокумент. Таким образом, мы можем видеть этот отрывок в браузере сC语言приветствия

Но, честно говоря, я не думаю, что WebAssembly может уменьшить количество кода, такого как этот простой код, скомпилированный в.wasmпозже понадобился12KB.

Фактическая защита кода

Например, изначальная JS-логика, которая мне нужна, выглядит следующим образом: каждый день по метке времени в 0:00 преобразовывать ее в 36-шестнадцатеричный формат, чтобы получить 6-значную строку (опыт ввода такой длины вполне дружелюбен). После того, как пользователь введет эту команду, можно активировать расширенную функцию.

Алгоритм в пруду с головастиками изменился, не наивно думайте, что я раскрою свой алгоритм :P

Как писать JS

function verifyCommand(cmd){
	var t_cmd = (new Date(new Date().setHours(0, 0, 0, 0)).getTime()/1000).toString(36);
	if(cmd == t_cmd)return 1;
	else return 0;
}

Но JS полностью открыт в браузере, и в режиме отладки браузера очень легко узнать, как генерируются расширенные команды.

Конечно, например, в начале этой статьи, мы можем проверить внутренний интерфейс.

Написание на PHP

function MyEncode($var,$targetBit){    
    $dic = array(
            0 => '0', 1 => '1', 2 => '2', 3 => '3', 4 => '4', 5 => '5', 6 => '6', 7 => '7', 8 => '8', 9 => '9',
            10 => 'A', 11 => 'B', 12 => 'C', 13 => 'D', 14 => 'E', 15 => 'F', 16 => 'G', 17 => 'H', 18 => 'I',
            19 => 'J', 20 => 'K', 21 => 'L', 22 => 'M', 23 => 'N', 24 => 'O', 25 => 'P', 26 => 'Q', 27 => 'R',
            28 => 'S', 29 => 'T', 30 => 'U', 31 => 'V', 32 => 'W', 33 => 'X', 34 => 'Y', 35 => 'Z'
    );
    $yushu=bcmod($var,$targetBit);
    $shang=floor(bcdiv($var, $targetBit));

    if($shang==0){
        return  $dic[$yushu];
    }
    else {
        return MyEncode($shang,$targetBit).$dic[$yushu];
    }
}

date_default_timezone_set('PRC');
$time =strtotime(date("Y-m-d 00:00:00"));
$v_cmd = MyEncode(intval($time),36);

$cmd = strtoupper($_GET["cmd"]);

if($cmd==$v_cmd){
    echo 1;
}else{
    echo 0;
}

Однако, если используется сервер, интерфейс необходимо запрашивать для каждой проверки, что, несомненно, будет давить на сервер.

Теперь мы используемC语言написать и, наконец, скомпилировать в WebAssembly.wasmдокумент

//获得今天零点的时间戳,秒
unsigned int getTodayZeroTime() 
{  
	//太长了,函数的实现请看源码
}  

//将数字转为指定进制,decimal为进制值
void f( long int x, char *p ,int decimal)
{
	//太长了,函数的实现请看源码
}

int verifyCommand(std::string cmd) {
  int t_time = getTodayZeroTime();
  char t_cmd[MAXN]="";
  f(t_time,t_cmd,36);

  if(strcmp(t_cmd, cmd.data()) == 0){
    return 1;
  }else{
    return 0;
  }
 }

JS-вызов.wasmМетод C и параметры передачи

Чтобы вызвать функцию в WebAssembly из JS, мы оборачиваем функцию внешним "C"

extern "C" {
  int verifyCommand(std::string cmd) {
    int t_time = getTodayZeroTime();
    char t_cmd[MAXN]="";
    f(t_time,t_cmd,36);

    if(strcmp(t_cmd, cmd.data()) == 0){
      return 1;
    }else{
      return 0;
    }
  }
}

при компиляции.wasmдобавить команду, когда

emcc verify.cc -o verify.html -s EXPORTED_FUNCTIONS="['_verifyCommand']" -s EXPORTED_RUNTIME_METHODS='["ccall"]'

Основное внимание уделяется этим двум параметрам, обратите внимание на символы подчеркивания и кавычки.

  • -s EXPORTED_FUNCTIONS="['_verifyCommand']"
  • -s EXPORTED_RUNTIME_METHODS='["ccall"]'

После завершения компиляции мы можем использовать JS для вызоваverifyCommandэтоC语言функционировать в

//第一个参数,函数名称
//第二个参数,函数返回值类型
//第三个参数,函数受参类型数组
//第四个参数,传递的参数数组
Module.ccall("verifyCommand",'number',['string'],['qmocg0']);

Ниже приведен скриншот окна отладки Я намеренно ввел правильно и неправильно, чтобы увидеть возвращаемое значение.

Теперь мы завершили функцию проверки этой расширенной команды, и проверку можно выполнить синхронно во внешнем интерфейсе напрямую, не запрашивая фоновый интерфейс для асинхронного получения результата проверки. Поскольку основной код находится в двоичном формате.wasmВ файле люди с сердцем не могут [легко] увидеть, как реализована логика в функции. Почему вы выделили слово "легкий"?

Поскольку его можно скомпилировать, его можно и декомпилировать...

На этом все в этой статье До встречи в пруду, все маленькие головастики Не забывайте ставить лайки и собирать, рано или поздно вам пригодится!

Следуйте за Дашуаем

Если вам нравятся уроки Дашуая, добавьте в закладки, лайкните и подпишитесь

  • Билибили:大帅老猿
  • Публичный аккаунт WeChat:大帅老猿