Rhino环境下如何保护Java对象字段不被JavaScript修改?
解决Rhino中JavaScript修改Java对象字段的问题
我明白你遇到的这个头疼问题——明明已经用initSafeStandardObjects()初始化了安全作用域,还调用了scope.sealObject()密封作用域,结果JavaScript代码还是能毫无阻碍地修改Java对象的字段。这其实是因为你当前的操作只限制了Rhino作用域本身的修改,并没有对Java对象的字段访问权限做控制。下面给你几个可行的解决方案:
1. 利用Java自身的访问控制(最直接的方案)
Rhino默认会尊重Java的访问修饰符,如果你的Java对象字段是private的,并且只提供只读的getter方法,不暴露setter,那么JavaScript就无法直接修改这些字段。
示例Java类:
public class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } // 只提供getter,不提供setter public String getName() { return name; } public int getAge() { return age; } }
当你把这个类的实例传入Rhino作用域后,JavaScript只能调用getName()和getAge()读取值,无法直接修改name或age字段。
2. 自定义WrapFactory控制Java对象的包装逻辑
Rhino通过WrapFactory来把Java对象包装成JavaScript可访问的对象,你可以重写它的方法来禁止对Java字段的修改操作。
示例代码:
Context cx = Context.enter(); try { cx.setOptimizationLevel(-1); // 自定义WrapFactory cx.setWrapFactory(new WrapFactory() { @Override public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class<?> staticType) { return new WrappedJavaObject(cx, scope, javaObject, staticType) { @Override public void put(String name, Scriptable start, Object value) { // 禁止修改Java对象的字段 throw new IllegalArgumentException("Cannot modify Java object field: " + name); } }; } }); // 初始化安全作用域 Scriptable sharedScope = cx.initSafeStandardObjects(new ImporterTopLevel(cx), true); // 添加你的Java对象到作用域 User user = new User("Alice", 25); sharedScope.put("user", sharedScope, Context.javaToJS(user, sharedScope)); // 密封作用域 sharedScope.sealObject(); // 测试JS代码 String jsCode = "user.name = 'Bob';"; // 执行时会抛出异常 cx.evaluateString(sharedScope, jsCode, "Test", 1, null); } finally { Context.exit(); }
这个方案会在JavaScript尝试修改Java对象字段时直接抛出异常,从根源阻止修改操作。
3. 转换为不可变的JavaScript对象
如果你不想修改原Java类的访问控制,可以把Java对象的字段值复制到一个新的JavaScript对象中,然后密封这个JS对象。这样JavaScript操作的是副本,不会影响原Java对象。
示例代码:
Context cx = Context.enter(); try { cx.setOptimizationLevel(-1); Scriptable sharedScope = cx.initSafeStandardObjects(new ImporterTopLevel(cx), true); User user = new User("Alice", 25); // 创建一个JS对象,复制Java对象的字段值 Scriptable immutableUser = cx.newObject(sharedScope); immutableUser.put("name", immutableUser, user.getName()); immutableUser.put("age", immutableUser, user.getAge()); // 密封这个JS对象,禁止修改 immutableUser.sealObject(); sharedScope.put("user", sharedScope, immutableUser); sharedScope.sealObject(); // 测试JS代码 String jsCode = "user.name = 'Bob'; console.log(user.name);"; // 输出还是Alice,修改无效 cx.evaluateString(sharedScope, jsCode, "Test", 1, null); } finally { Context.exit(); }
为什么你的原有操作无效?
最后再解释下:
initSafeStandardObjects()只是禁用了JavaScript中的危险全局对象(比如eval、Function的某些危险用法),并没有限制Java对象的访问。scope.sealObject()是密封Rhino的作用域对象,防止向作用域中添加/删除属性,但不影响作用域内已存在的Java对象的字段修改。
内容的提问来源于stack exchange,提问作者Betalord
相关产品推荐
相关产品推荐

