You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Simple JS子集分析器?验证JS代码是否符合限定功能

实现Simple JS子集分析器的步骤

要做一个基于允许列表的JS子集检查器,核心思路是通过AST(抽象语法树)分析代码结构,逐一验证每个语法节点和API调用是否符合规则。下面是具体实现步骤:

1. 明确允许的语法与API范围

先把规则落地成清晰的列表,避免模糊:

允许的语法

  • 变量定义与修改:var/let/const声明、变量赋值
  • 函数相关:普通函数声明、函数表达式、箭头函数(非async)
  • 基础语句:条件判断(if/else)、循环(for/while)、return语句
  • 基础表达式:字面量(数字、字符串、布尔值)、标识符、二元/一元运算

禁止的内容

  • 语法层面:async/await、生成器函数、with语句、try/catch(按需调整)
  • API层面:eval、Function构造函数、网络操作(fetch/XMLHttpRequest)、定时器(setTimeout/setInterval,按需调整)

2. 选择AST解析工具

用成熟的JS解析器生成AST,推荐Acorn或Esprima,都是轻量、易集成的工具,直接通过npm安装即可。

3. 编写AST遍历与检查逻辑

解析代码生成AST后,遍历每个节点,对照允许列表做校验:

  • 检查节点类型:如果节点类型不在允许列表里,直接标记错误
  • 检查异步语法:如果函数(含箭头函数)带有async标记,或者遇到await表达式,直接禁止
  • 检查API调用:遍历所有函数调用节点,判断是否调用了禁止的API(包括全局函数和对象方法,比如window.fetch)
  • 检查危险构造:比如new Function()这种动态代码生成的方式,直接禁止

示例代码

下面是用Acorn+acorn-walk实现的极简检查器:

# 先安装依赖
npm install acorn acorn-walk
const acorn = require('acorn');
const walk = require('acorn-walk');

// 允许的AST节点类型集合
const ALLOWED_NODE_TYPES = new Set([
  'Program', 'BlockStatement',
  'VariableDeclaration', 'VariableDeclarator',
  'AssignmentExpression',
  'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression',
  'Literal', 'Identifier',
  'BinaryExpression', 'UnaryExpression',
  'IfStatement', 'ForStatement', 'WhileStatement',
  'ReturnStatement', 'ExpressionStatement'
]);

// 禁止的全局API/构造函数
const FORBIDDEN_APIS = new Set([
  'eval', 'fetch', 'XMLHttpRequest', 'Function',
  'setTimeout', 'setInterval'
]);

function checkSimpleJS(code) {
  let ast;
  // 先做语法校验
  try {
    ast = acorn.parse(code, { ecmaVersion: 2020 });
  } catch (err) {
    return { valid: false, errors: [`代码语法错误: ${err.message}`] };
  }

  const errors = [];

  // 遍历AST节点
  walk.simple(ast, {
    enter(node) {
      // 检查节点类型是否合法
      if (!ALLOWED_NODE_TYPES.has(node.type)) {
        errors.push(`非法语法: ${node.type}`);
      }
      // 检查是否是async函数
      if (['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'].includes(node.type) && node.async) {
        errors.push('禁止使用async函数');
      }
    },

    // 检查函数调用
    CallExpression(node) {
      // 直接调用全局函数,比如 eval()
      if (node.callee.type === 'Identifier' && FORBIDDEN_APIS.has(node.callee.name)) {
        errors.push(`禁止调用API: ${node.callee.name}`);
      }
      // 调用对象方法,比如 window.fetch()
      if (node.callee.type === 'MemberExpression') {
        const propName = node.callee.property.name;
        if (FORBIDDEN_APIS.has(propName)) {
          errors.push(`禁止调用API: ${propName}`);
        }
      }
    },

    // 专门检查await表达式
    AwaitExpression() {
      errors.push('禁止使用await');
    },

    // 检查new构造函数,比如 new XMLHttpRequest()
    NewExpression(node) {
      if (node.callee.type === 'Identifier' && FORBIDDEN_APIS.has(node.callee.name)) {
        errors.push(`禁止使用构造函数: ${node.callee.name}`);
      }
    }
  });

  return {
    valid: errors.length === 0,
    errors: errors
  };
}

// 测试用例
const validCode = `
  let count = 0;
  const max = 10;
  function increment() {
    count += 1;
    return count;
  }
  const double = num => num * 2;
  while (count < max) {
    count = double(increment());
  }
`;

const invalidCode = `
  async function loadData() {
    const resp = await fetch('/data');
    const result = eval(resp.text());
  }
`;

console.log('合法代码检查结果:', checkSimpleJS(validCode));
console.log('非法代码检查结果:', checkSimpleJS(invalidCode));

4. 优化与扩展

  • 可以给错误信息加上行号和列号,Acorn生成的AST节点包含loc属性,能定位代码位置
  • 如果需要支持更多基础语法(比如switch语句),直接把对应的节点类型加到允许列表里
  • 可以扩展API检查,比如禁止访问window对象的危险属性,或者自定义全局变量的使用

内容的提问来源于stack exchange,提问作者pir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:50:40