Создание дезинфицирующего средства для eval в Angular - что удалить? - PullRequest
0 голосов
/ 20 апреля 2020

Я работаю над приложением Angular 8 PWA, которое позволяет пользователям создавать свои собственные формы. В рамках этой функции существует требование, позволяющее администраторам создавать пользовательские сценарии для выполнения вычислений в определенных полях.

Для этого я реализую eval в сочетании с дезинфицирующим средством, выполненным из службы angular. Поскольку скрипту нужно только основать c logi c (если, еще и циклы) + частные функции, мы удаляем большую часть всего потенциально опасного кода.

У меня есть стекблиц от дезинфицирующего средства и базовый c пример + код ниже. Sanitizer Stackblitz

Как работает Sanitizer

Как работает sanitizer, он разбивает код на токены массива, например ((['if' , 'else', '(']. Затем каждый токен проходит через черный список токенов, которые мы не хотим включать в код, чтобы предотвратить выполнение вредоносного кода. В случае обнаружения код не будет разрешен к использованию. Выполнено.

Вот черный список:

1. require (prevent other scripts)
2. new (no creation of interfaces eg new date(), new fileReader. If required will be done via private function)
3. window
4. document (prevent dom manipulation)
5. eval
6. navigator
7. blacklist (prevent manipulation to variable in service)
8. this (prevent access any methods within in service)
9...13. script , id , div , #id , class (main tags in html)

Мой вопрос: Есть ли что-нибудь еще в черном списке, который я должен включить или пропустить, чтобы предотвратить выполнение любого вредоносного кода?

Ценю все отзывы. Большое спасибо заранее.

Служба сценариев

import { Injectable } from '@angular/core';
import * as _ from 'lodash';
@Injectable({
  providedIn: 'root'
})
export class ScriptService {
  blacklist: string[] = ['require', 'new', 'window','script', 'eval', 'document','blacklist', 'this', 'navigator', 'div', 'id','#id','class'];
  constructor() { }

  /*
  ** name: Tokenize String
  ** desc: Convert string script into tokens and trim spaces
  */
  tokenizeString(code: string):string[] {
    let tokens: string[] = code.match(/\w+|\W+/g).map(function(value){return value.trim()});
    return tokens;
  }
  /*
  ** name: Check Script
  ** desc: Checks for script for any blacklist item
  */
  checkScriptSafe(code: string):boolean {
    let blacklist: string[] = this.blacklist;
    let tokens: string[] = this.tokenizeString(code);
    for (let i = 0; i < tokens.length; ++i) {
      let token: string = tokens[i];
      if (blacklist.indexOf(token) > -1) {
        return false;
      }
    }
    return true;
  }
  /*
  ** name: Get Field
  ** desc: example of custom method available to the custom script
  */
  getField(id: string): any {
    // basic field retrieval to show working functions
    if (id === 'field1') {
      return 'value1';
    }
    if (id === 'field2') {
      return 'value2';
    }
  }

  // Sandbox script
  runScript(code: string):void {
    // access to method as private function
    let getField = (id: string)=>{
      return this.getField(id);
    }

    if (!this.checkScriptSafe(code)) {
      alert('Unable to run script! Contains syntax which is not allowed.');
      return;
    }
    // script safe to run
    eval(code);
  }
}
...