tc39 / proposal-cancelable-promises

Former home of the now-withdrawn cancelable promises proposal for JavaScript
Other
375 stars 29 forks source link

Security implications of introducing cancel-throw completion values #24

Closed bergus closed 8 years ago

bergus commented 8 years ago

I see many other problems with introducing a new completion type, but in this issue I want to discuss the security implications. Does this allow new kinds of attacks on code that was not designed to cope with cancellations? I say yes. Consider the following crude example

var state = …;
var acting = false;
userInput.on("act", function(action) {
    var copy = state.clone();
    try {
        acting = true;
        action(state);
        if (isInvalid(state)) throw new ValidationError(…);
        …
    } catch (e) { // if anything bad happens
        state.restore(copy); // go back to previous state and we're good again
    } finally {
        acting = false;
    }
});
userInput.on("submit", function() {
    if (!acting)
        state.saveToDatabase();
});

Here the user is allowed to supply some action, but we ensure our state never becomes invalid. It's even guarded against reentrancy so that the user cannot fire a submit event during his action.

However, the picture changes with cancel throw. Here the user can do

userInput.emit("act", function(state) {
    makeInvalid(state);
    cancel throw null;
});

and when he later submits, we do have a problem.

domenic commented 8 years ago

This is common feedback, that introducing new code into environments that are not expecting it is an issue. It's on my to-do list to address it, but there are two immediate responses:

  1. This is a common problem when introducing any new language feature. An easy example is proxies, where you can make code throw (or do any arbitrary computation) that was never expecting it before.
  2. You can always contain the problem by wrapping. Instead of passing the old code a function f, pass it function () { try { return f.apply(this, arguments); } cancel catch (e) { } }, and it will never see any cancel catch completions.
bergus commented 8 years ago

This is common feedback

Ah, I had not seen it before, so I just thought to open an issue. Glad that you were going to address it anyway.

An easy example is proxies, where you can make code throw (or do any arbitrary computation) that was never expecting it before.

Hm, expecting user-supplied code or values to throw (e.g. with a getter) is one thing, expecting it not to return but still return (not hang) is another thing.

domenic commented 8 years ago

New approach no longer experiences this issue.

bergus commented 8 years ago

Thanks!