Controlling DontEnum (was: ES4 draft: Object)
Mark S. Miller
erights at google.com
Thu Mar 13 16:21:43 PDT 2008
>> From: Neil Mix [mailto:nmix at pandora.com]
>> function __createProperty__(name:EnumerableId,
>> writable:boolean=true): void
On Thu, Mar 13, 2008 at 2:21 PM, Lars Hansen <lhansen at adobe.com> wrote:
> This feels like convergence. I'll hook this into the RI and
> write it up in the next couple of days (barring further
> discussion, of course).
I've been following this discussion and am quite happy with the
overall direction! With these changes, ES3.1 should be a much
friendlier base to subset into a Caja-like secure language. I'm
hopeful that the resulting Caja-like language could safely be a much
larger subset of ES3.1 than with current Caja vs ES3. I haven't yet
thought these issues through well, but I'll offer some half baked
suggestions for now.
* As someone pointed out, using positional boolean flag parameters
(..., false, true, false, ...) makes call-site readability too hard.
This point was raised earlier but seems to have been dropped. IIRC,
*all* the other parameterization suggestions had better call site
readability. My favorite was simply a list of strings. OTOH, an
advantage of the bit-mask approach is that sensible combinations of
flags can be named and used simply.
* I love Neil's suggestion of moving towards names saying what's
allowed, rather than saying what's denied. I'd like to go further and
suggest that __createProperty__ adopt the security best-practice of
default-deny: When a property is explicitly created by this mechanism,
only those operations that are explicitly allowed are permitted. All
others attributes default to denying permission. To maintain
compatibility of course, a property created the old fashioned way is
implicitly fully permissive.
* As Brendan reminds us, an erroneous __createProperty__ request
should throw rather than failing silently or merely returning false.
And a property access that fails because __createProperty__ did not
allow it should also fail with a throw rather than silently. If we
want to be strictly legacy compatible, then these throws should only
happen for properties created with __createProperty__. Unfortunately,
that means the semantics and implementations would need to
distinguish, for example, legacy silently non-writable properties from
new noisily non-writable properties. Can we instead specify that all
these failures will be noisy?
* Kris raises, we need to think about the interaction of these
attributes with the notion of virtual properties defined using getters
and setters. In particular, how does one create a non-removable
virtual property? Should virtual properties have deleters in addition
to getters and setters?
* Might there be a sensible way to extend this mechanism to
distinguish public from non-public properties? Based on the Caja
design, might we adopt the rule that non-public property foo can only
be addressed as this.foo or this['foo']. In other words, x.foo would
only work is foo is public or unrestricted.
The general approach we're following here for properties is: default
to legacy-compatible overly-permissive behavior, but allow restriction
to a fail-stop subset of this behavior. We should prefer to make
expressible those restrictions that contribute to reasoning about
integrity. (This is the right criteria whether on not one is trying to
define a secure subset.)
We should apply this general approach to objects as well as individual
properties of objects. The most important, borrowed from ES4, is
fixture vs dynamic. The Caja concept "frozen" then becomes exactly:
fixture + all existing properties are non-writable and non-removable.
We can even use this approach to clean up the main source of confusion
in ES3 while preserving compatibility: What is the intended behavior
of a function? It would be great to explicitly restrict a function to
be callable only as a function, or only as a method, or only as a
constructor, or only as a final constructor. An unrestricted function
could continue to be callable in all these ways, as with ES3
functions. Moving these restrictions into the language would clear up
a major source of vulnerability in the current Caja design: confused
deputy dangers at the taming boundary between cajoled code and
uncajoled code. If there's interest, I can expand on this issue.
More information about the Es4-discuss