Last week it came out that, in Firefox (and other Gecko-based browsers) you could dip into the private scope of a function using eval, like so:
// Getting "private" variables var obj = (function() { var a = 21; return { // public function must reference 'a' fn: function() {a;} }; })(); var foo; eval('foo=a', obj.fn); console.log(foo); // 21
I think the common response to seeing the above was something like: WUH!?!?
As can be seen in the ensuing discussions.
Perhaps more interestingly is the dig in to try and figure out how on earth this feature made it in to the language to being with. Brendan Eich provides some insight:
3.2 <fur> 1998-04-23 17:30: Initial checkin of JavaScript 1.3, migrated from JSFUN13_BRANCH in /m/ src repository
This eval extension, if memory serves (I was in mozilla.org at the time, not in the JS group at Netscape) originated in conversations with Microsoft’s rep during ECMA-262 standardization, trying to reach agreement on a way to eval in other scopes.
At this point, however, it’s pretty safe to say that since so few people know about it, and that (hopefully) there are no important sites relying upon its behavior, it can be stricken from the record.
It’s been a crazy ride but you can expect to see this feature gone in Firefox 3.1 (the next release of Firefox, set to debut this year).
crowder (July 2, 2008 at 3:18 pm)
fyi, I’ve just asked in the bug to try to get this in for 1.9.0.2.
Robbert Broersma (July 2, 2008 at 3:25 pm)
Funny that security is the reason to disable this feature, as the second argument can also be used to sandbox scripts: eval(‘alert(window)’, {}) will alert ‘undefined’.
Andrea Giammarchi (July 2, 2008 at 3:27 pm)
Damn, John, You too!!!
After I read your post, I had to write a solution to make our dreams more sweet :D
I hope somebody else will agree with me that this is a feature, and not a bug … but this time, I am pretty much sure, they will not reintroduce this amazing possibility!
I don’t know if I should say “thanks”, or dhò!!!
Andrea Giammarchi (July 2, 2008 at 3:31 pm)
@Robbert … exactly, we are going to loose a lot of possibilities because everybody, even without a single eval in their code, now is scared about closures!
I have just written a simple solution that works “specially” with Gecko, and that is not a problem for performances at all, since I guess we are not using eval inside a loop, but once a page (or once every few seconds and never more).
John Resig (July 2, 2008 at 3:34 pm)
@crowder: Yep, just saw that – we’ll have to see if that happens, considering that it changes API.
@Robbert: That’s very cool – I wonder how you get the alert function, then, I wonder – since it, itself, is a property on the global object.
@Andrea: I’m not against this feature for a technical reason, per se (I fully agree that some very cool stuff could be done with it) – I’m against it because it introduces something that is completely unexpected and breaks many of the idioms that JavaScript presents. I think we should explore other ways to make these cool side effects occur, instead.
Leo Horie (July 2, 2008 at 3:50 pm)
I don’t really understand what’s the security issue with eval(string, fn) in particular. Considering how this refers to a browser’s javascript engine, couldn’t we simply download and run scripts in some Rhino mashup (LoboBrowser comes to mind) or whatever and have every “private” variable available to the underlying engine anyways? One could also just overwrite the entire obj variable…
If the concern is with XSS, I thought eval in itself was already evil :)
I’d actually agree with Robbert that having the second parameter would indeed make sandboxing untrusted scripts a whole lot easier than not having it.
Andrea Giammarchi (July 2, 2008 at 3:54 pm)
I would like to be able to delete eval; and redeclare them via a constant using a closure, instead of kill this possibility.
I agree that this is unexpected, but we are removing a new JS scenario, instead of using them.
What is unexpected, is that in my mind Mozilla team did not think enough about the “problem” and closed the bug instantly.
This is the best thing of Mozilla staff, but this time, probably not the best choice.
Andrea Giammarchi (July 2, 2008 at 3:57 pm)
@Leo … you did the point, as I wrote in my post there is no reason at all to be worried about this feature, because if it is dangerous for our site, it means that there are a lot of problems over the second argument. Eval could be assigned again, lie eval = myfunction, so this is possible, but everybody is scared about a powerful second argument.
It does not make sense at all, but these are only our opinion, because the bug has been already closed.
TNO (July 2, 2008 at 6:05 pm)
Here’s what i came up with on the Ajaxian thread:
var obj = function(){
var a = 21;
return {
prop : undefined,
get prop(){return a},
set prop(x){
if ((typeof x === “function”) || (typeof x === "object")) {
return false;
} else {
a = x;
}
}
}
}();
Kyle Simpson (July 2, 2008 at 11:10 pm)
I think Andrea’s solution is on the right line. I don’t think this “feature” should be removed as a bug from FF3.1.
I think clearly though there are some objects which would want to be able to maintain their privacy (ie, “keep their blinds closed and their door locked”). Specifically, it’s not really the access to private data, but the access to OVERWRITE private data or methods, that is most “scary” about the feature, given some types of JS objects that have been written which heretofore have relied on being able to keep themselves intact.
I believe a “smart” eval is the way to go, which would allow this functionality of introspection/closure reflection by default on all object instances, but where an object could somehow signal to eval that it wanted to opt out of this “intrusion” and the eval would respect that and not let them in.
So, along those lines, the redefinition of eval that Andrea shows, as a constant, could be a more complex object of sorts, which checks an object for this “permission” before it allows the second parameter through or not.
In this way, the benefits of the feature can be kept, but those few objects which really want to can still opt out and maintain their “illusion of privacy”.
Mook (July 3, 2008 at 12:12 am)
Wouldn’t making it work as expected be a much better fix? Instead of using the function’s scope, just have a scope where its properties exist. In fact, just like a with. I’d expect Components.utils.import and mozISubScriptLoader to act the same way, but I don’t know if they do.
Having the documentation suggest the use of with as an alternative is rather funny, given that you get a warning in the JS console every time you use it.
voracity (July 3, 2008 at 12:25 am)
Gah! This security witch-hunt is turning JS into a very dull language. We should be pushing for JS to have a more thorough (reflective) object model, not less thorough.
Neil Mosafi (July 3, 2008 at 3:43 am)
Agree with Leo Horie’s points myself. This is Akin to saying we should remove Reflection from .NET or Java because it lets code read into private variables. What difference does it make?
Andrea Giammarchi (July 3, 2008 at 3:46 am)
Another example about how a misunderstand feature could be the solution to obtain safer environment (sorry John, it is not spam, but anyway will be the last one :D)
Andrea Giammarchi (July 3, 2008 at 6:07 am)
bug REOPENED, hoping they will reverse those changes :)
William from Lagos (July 4, 2008 at 5:41 am)
Interesting functionality. Never knew about this. Could any one please explain the use of eval in this manner, stating examples, use-cases, pros and cons.
Thanks.
DavidJCobb (July 4, 2008 at 6:06 pm)
So, lemme get this straight.
They had an infinitely useful (albeit accidental) feature that could be used not only to assist in debugging but also in sandboxing, and they REMOVED it?!
Quite possibly the ULTIMATE debugging assistant, and they REMOVED IT?!
Very likely the ULTIMATE sandboxing method, and they REMOVED IT?!
A far better solution would be to have this function disabled for all objects by default, and objects could “opt in” to make this technique possible. Like, it’d be disabled by default and objects could set a special property (perhaps “MozAllowScopedEval” or something similar) to allow the technique to be used on them.
Nosredna (July 6, 2008 at 12:57 am)
Yeah, don’t remove it so fast.
DavidJCobb (March 3, 2009 at 8:15 pm)
Well. Now that I have a far better understanding of private methods/properties and closures, I actually think that this should be removed.