Using Google Caja to run user-supplied Javascript

2019-02-16 00:57发布

问题:

It appears that the official examples use a caja.js file that just wraps an iframe to load an URL from a server hosting a caja compilation service, which in turn, gets its input from some URL. The relevant API for that is available here.

However, what I really want is to just safely (and repeatedly) run a user-supplied piece of Javascript, like so:

for (var i = 0; i < N; ++i) {
    var x = getUserResult(currentState);
    updateState(currentState, x);
}

Is there any way to do this directly? The code here has the compiler. Why can't I just use that to compile the code and then run that within an emulated context? Is it because the only way to get a safe context in a browser is an iframe? And, if so, is there any way I can use an iframe to directly run given source code, without having to fetch it from an external URL?

回答1:

Caja needs an iframe no matter what. Both modes of execution require a set of JavaScript globals (obtained by creating the frame) which is available to be radically modified to enable safe execution.

Modern Caja (ES5 mode) does not require any server-side compilation step; provided the browser is compatible you can use Caja in the standard way and the server will never be contacted. To force this, specify es5Mode: true in the options to caja.initialize.

You can load guest code once and repeatedly execute it; just provide an api which lets the guest pass a function out when it's loaded, then call the function whenever you like.


For your use case, it would also be possible to use SES, the modern safe-eval subsystem of Caja, without using Caja itself at all; this would allow you to skip having any iframes, but would require you to write your code in a SES-compatible way; that is,

  • refraining from modifying global objects such as Object.prototype, and
  • protecting all objects directly or indirectly exposed to the user-supplied code using Object.freeze().)

If you're up for it, I do recommend using SES directly, as it removes a lot of indirections and total complexity, but it does require understanding the concepts to succeed at safety.