Object.freeze(Object.prototype) VS reality
On Thu, Feb 19, 2015 at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote:
It's obviously possible to replace all built-in props by accessors [4], of course, but this is a bit ridiculous.
It is indeed ridiculous. Not fixing this in the ES5 timeframe was my single biggest failure and disappointment as a member of TC39.
For reference, Caja's implementation of the technique described in [4] is at
code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#278
As it states, our term for freezing an object so that it does not provoke this problem is "tamper proofing".
Can the override mistake be fixed? I imagine no web compat issues would occur since this change is about throwing less errors.
There was a time when some of the browsers did not suffer from the override mistake, and in so doing, were technically out of conformance with the ES5 spec. During this window, it was clearly still web compatible to fix the override mistake. It was during this window that I raised the issue and argued that it be fixed. I brought this up in meetings several times and never made any progress. Once all browsers suffered equally from the override mistake, it was no longer clearly web compatible to fix it, so I gave up and focused on other things instead.
However, I agree with your suspicion that it actually would still be web compatible to fix this. Unfortunately, the only way to find out at this point is for a browser to try deploying without the override mistake. I don't have much hope.
Instead, I suggest you promote tamper proofing to those audiences to which you currently promote freezing. Though the need for it is indeed ridiculous, it actually works rather well. We've been using it successfully for many years now.
On Thu, Feb 19, 2015 at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote: > Hi, > > Half a million times the following meta-exchange happened on es-discuss: > - if an attacker modifies Object.prototype, then you're doomed in all > sorts of ways > - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! > > I've done it on client-side projects with reasonable success. I've just > tried on a Node project and lots of dependencies started throwing errors. > (I imagine the difference is that in Node, it's easy to create projects > with a big tree of dependencies which I haven't done too much on the client > side). > > I tracked down a few of these errors and they all seem to relate to the > override mistake [1]. > * In jsdom [2], trying to add a "constructor" property to an object fails > because Object.prototype.constructor is configurable: false, writable: false > * in tough-cookie [3] (which is a dependency of the popular 'request' > module), trying to set Cookie.prototype.toString fails because > Object.prototype.toString is configurable: false, writable: false > > Arguably, they could use Object.defineProperty, but they won't because > it's less natural and it'd be absurd to try to fix npm. The > Cookie.prototype.toString case is interesting. Of all the methods being > added, only toString causes a problem. Using Object.defineProperty for this > one would be an awkward inconsistency. > > > So, we're in a state where no module needs to modify Object.prototype, but > I cannot freeze it because the override mistake makes throw any script that > tries to set a toString property to an object. > Because of the override mistake, either I have to let Object.prototype > mutable (depite no module needing it to be mutable) or freeze it first hand > and not use popular modules like jsdom or request. > > It's obviously possible to replace all built-in props by accessors [4], of > course, but this is a bit ridiculous. > It is indeed ridiculous. Not fixing this in the ES5 timeframe was my single biggest failure and disappointment as a member of TC39. For reference, Caja's implementation of the technique described in [4] is at https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#278 As it states, our term for freezing an object so that it does not provoke this problem is "tamper proofing". > Can the override mistake be fixed? I imagine no web compat issues would > occur since this change is about throwing less errors. > There was a time when some of the browsers did not suffer from the override mistake, and in so doing, were technically out of conformance with the ES5 spec. During this window, it was clearly still web compatible to fix the override mistake. It was during this window that I raised the issue and argued that it be fixed. I brought this up in meetings several times and never made any progress. Once all browsers suffered equally from the override mistake, it was no longer *clearly* web compatible to fix it, so I gave up and focussed on other things instead. However, I agree with your suspicion that it actually would still be web compatible to fix this. Unfortunately, the only way to find out at this point is for a browser to try deploying without the override mistake. I don't have much hope. Instead, I suggest you promote tamper proofing to those audiences to which you currently promote freezing. Though the need for it is indeed ridiculous, it actually works rather well. We've been using it successfully for many years now. > > David > > [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ > override_mistake > [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 > 1aff1db291/lib/jsdom/utils.js#L65-L95 > [3] https://github.com/goinstant/tough-cookie/blob/ > c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 > [4] https://github.com/rwaldron/tc39-notes/blob/ > c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- > 25.md#fix-override-mistake-aka-the-can-put-check > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -- Cheers, --MarkM -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/2bf650be/attachment.html>
Just as workaround, if you really need that much to freeze the
Object.prototype
, you could:
Object
.getOwnPropertyNames(Object.prototype)
.filter((name) => !/^constructor|toString|valueIOf$/.test(name))
.forEach((name) => Object.defineProperty(
Object.prototype,
name,
{value: Object.prototype[name]}
))
;
Object.preventExtensions(Object.prototype);
You can eventually fix those 3 properties somehow via accessors.
Not ideal, but it should hopefully make your project work (at least)
Just as workaround, if you really need that much to freeze the `Object.prototype`, you could: ```js Object .getOwnPropertyNames(Object.prototype) .filter((name) => !/^constructor|toString|valueIOf$/.test(name)) .forEach((name) => Object.defineProperty( Object.prototype, name, {value: Object.prototype[name]} )) ; Object.preventExtensions(Object.prototype); ``` You can eventually fix those 3 properties somehow via accessors. Not ideal, but it should hopefully make your project work (at least) Best Regards On Thu, Feb 19, 2015 at 5:23 PM, David Bruant <bruant.d at gmail.com> wrote: > Hi, > > Half a million times the following meta-exchange happened on es-discuss: > - if an attacker modifies Object.prototype, then you're doomed in all > sorts of ways > - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! > > I've done it on client-side projects with reasonable success. I've just > tried on a Node project and lots of dependencies started throwing errors. > (I imagine the difference is that in Node, it's easy to create projects > with a big tree of dependencies which I haven't done too much on the client > side). > > I tracked down a few of these errors and they all seem to relate to the > override mistake [1]. > * In jsdom [2], trying to add a "constructor" property to an object fails > because Object.prototype.constructor is configurable: false, writable: false > * in tough-cookie [3] (which is a dependency of the popular 'request' > module), trying to set Cookie.prototype.toString fails because > Object.prototype.toString is configurable: false, writable: false > > Arguably, they could use Object.defineProperty, but they won't because > it's less natural and it'd be absurd to try to fix npm. The > Cookie.prototype.toString case is interesting. Of all the methods being > added, only toString causes a problem. Using Object.defineProperty for this > one would be an awkward inconsistency. > > > So, we're in a state where no module needs to modify Object.prototype, but > I cannot freeze it because the override mistake makes throw any script that > tries to set a toString property to an object. > Because of the override mistake, either I have to let Object.prototype > mutable (depite no module needing it to be mutable) or freeze it first hand > and not use popular modules like jsdom or request. > > It's obviously possible to replace all built-in props by accessors [4], of > course, but this is a bit ridiculous. > Can the override mistake be fixed? I imagine no web compat issues would > occur since this change is about throwing less errors. > > David > > [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ > override_mistake > [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 > 1aff1db291/lib/jsdom/utils.js#L65-L95 > [3] https://github.com/goinstant/tough-cookie/blob/ > c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 > [4] https://github.com/rwaldron/tc39-notes/blob/ > c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- > 25.md#fix-override-mistake-aka-the-can-put-check > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/b513d3bd/attachment-0001.html>
this, and the fact descriptors suffer inheritance which for 3 boolean
properties or a method are absolutely not helpful and make the env doomed
by Object.prototype.writable = true
shenanigans.
Yes, I'd personally +1 all these fixes that made these ES5 features not the easiest one to play with
this, and the fact descriptors suffer inheritance which for 3 boolean properties or a method are absolutely not helpful and make the env doomed by `Object.prototype.writable = true` shenanigans. Yes, I'd personally +1 all these fixes that made these ES5 features not the easiest one to play with On Thu, Feb 19, 2015 at 5:41 PM, Mark S. Miller <erights at google.com> wrote: > On Thu, Feb 19, 2015 at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote: > >> Hi, >> >> Half a million times the following meta-exchange happened on es-discuss: >> - if an attacker modifies Object.prototype, then you're doomed in all >> sorts of ways >> - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! >> >> I've done it on client-side projects with reasonable success. I've just >> tried on a Node project and lots of dependencies started throwing errors. >> (I imagine the difference is that in Node, it's easy to create projects >> with a big tree of dependencies which I haven't done too much on the client >> side). >> >> I tracked down a few of these errors and they all seem to relate to the >> override mistake [1]. >> * In jsdom [2], trying to add a "constructor" property to an object fails >> because Object.prototype.constructor is configurable: false, writable: false >> * in tough-cookie [3] (which is a dependency of the popular 'request' >> module), trying to set Cookie.prototype.toString fails because >> Object.prototype.toString is configurable: false, writable: false >> >> Arguably, they could use Object.defineProperty, but they won't because >> it's less natural and it'd be absurd to try to fix npm. The >> Cookie.prototype.toString case is interesting. Of all the methods being >> added, only toString causes a problem. Using Object.defineProperty for this >> one would be an awkward inconsistency. >> >> >> So, we're in a state where no module needs to modify Object.prototype, >> but I cannot freeze it because the override mistake makes throw any script >> that tries to set a toString property to an object. >> Because of the override mistake, either I have to let Object.prototype >> mutable (depite no module needing it to be mutable) or freeze it first hand >> and not use popular modules like jsdom or request. >> >> It's obviously possible to replace all built-in props by accessors [4], >> of course, but this is a bit ridiculous. >> > > It is indeed ridiculous. Not fixing this in the ES5 timeframe was my > single biggest failure and disappointment as a member of TC39. > > For reference, Caja's implementation of the technique described in [4] is > at > > > https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#278 > > As it states, our term for freezing an object so that it does not provoke > this problem is "tamper proofing". > > > >> Can the override mistake be fixed? I imagine no web compat issues would >> occur since this change is about throwing less errors. >> > > There was a time when some of the browsers did not suffer from the > override mistake, and in so doing, were technically out of conformance with > the ES5 spec. During this window, it was clearly still web compatible to > fix the override mistake. It was during this window that I raised the issue > and argued that it be fixed. I brought this up in meetings several times > and never made any progress. Once all browsers suffered equally from the > override mistake, it was no longer *clearly* web compatible to fix it, so I > gave up and focussed on other things instead. > > However, I agree with your suspicion that it actually would still be web > compatible to fix this. Unfortunately, the only way to find out at this > point is for a browser to try deploying without the override mistake. I > don't have much hope. > > Instead, I suggest you promote tamper proofing to those audiences to which > you currently promote freezing. Though the need for it is indeed > ridiculous, it actually works rather well. We've been using it successfully > for many years now. > > > > >> >> David >> >> [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ >> override_mistake >> [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 >> 1aff1db291/lib/jsdom/utils.js#L65-L95 >> [3] https://github.com/goinstant/tough-cookie/blob/ >> c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 >> [4] https://github.com/rwaldron/tc39-notes/blob/ >> c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- >> 25.md#fix-override-mistake-aka-the-can-put-check >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > > > > -- > Cheers, > --MarkM > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/b161d2a1/attachment.html>
On Thu, Feb 19, 2015 at 9:54 AM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
Just as workaround, if you really need that much to freeze the
Object.prototype
, you could:
Your defineProperty call above has no effect. When doing a defineProperty on an existing property, recall that omitting attributes means that the setting of these attributes should not be changed. Omitted attributes only default to false when the property does not already exist.
Interesting that I've seen this bug several times now, by several different authors. Apparently, it is an unanticipated footgun in the ES5 reflection API.
On Thu, Feb 19, 2015 at 9:54 AM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote: > Just as workaround, if you really need that much to freeze the > `Object.prototype`, you could: > > ```js > Object > .getOwnPropertyNames(Object.prototype) > .filter((name) => !/^constructor|toString|valueIOf$/.test(name)) > .forEach((name) => Object.defineProperty( > Object.prototype, > name, > {value: Object.prototype[name]} > )) > Your defineProperty call above has no effect. When doing a defineProperty on an existing property, recall that omitting attributes means that the setting of these attributes should not be changed. Omitted attributes only default to false when the property does not already exist. Interesting that I've seen this bug several times now, by several different authors. Apparently, it is an unanticipated footgun in the ES5 reflection API. > ; > Object.preventExtensions(Object.prototype); > ``` > > You can eventually fix those 3 properties somehow via accessors. > > Not ideal, but it should hopefully make your project work (at least) > > Best Regards > > > On Thu, Feb 19, 2015 at 5:23 PM, David Bruant <bruant.d at gmail.com> wrote: > >> Hi, >> >> Half a million times the following meta-exchange happened on es-discuss: >> - if an attacker modifies Object.prototype, then you're doomed in all >> sorts of ways >> - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! >> >> I've done it on client-side projects with reasonable success. I've just >> tried on a Node project and lots of dependencies started throwing errors. >> (I imagine the difference is that in Node, it's easy to create projects >> with a big tree of dependencies which I haven't done too much on the client >> side). >> >> I tracked down a few of these errors and they all seem to relate to the >> override mistake [1]. >> * In jsdom [2], trying to add a "constructor" property to an object fails >> because Object.prototype.constructor is configurable: false, writable: false >> * in tough-cookie [3] (which is a dependency of the popular 'request' >> module), trying to set Cookie.prototype.toString fails because >> Object.prototype.toString is configurable: false, writable: false >> >> Arguably, they could use Object.defineProperty, but they won't because >> it's less natural and it'd be absurd to try to fix npm. The >> Cookie.prototype.toString case is interesting. Of all the methods being >> added, only toString causes a problem. Using Object.defineProperty for this >> one would be an awkward inconsistency. >> >> >> So, we're in a state where no module needs to modify Object.prototype, >> but I cannot freeze it because the override mistake makes throw any script >> that tries to set a toString property to an object. >> Because of the override mistake, either I have to let Object.prototype >> mutable (depite no module needing it to be mutable) or freeze it first hand >> and not use popular modules like jsdom or request. >> >> It's obviously possible to replace all built-in props by accessors [4], >> of course, but this is a bit ridiculous. >> Can the override mistake be fixed? I imagine no web compat issues would >> occur since this change is about throwing less errors. >> >> David >> >> [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ >> override_mistake >> [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 >> 1aff1db291/lib/jsdom/utils.js#L65-L95 >> [3] https://github.com/goinstant/tough-cookie/blob/ >> c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 >> [4] https://github.com/rwaldron/tc39-notes/blob/ >> c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- >> 25.md#fix-override-mistake-aka-the-can-put-check >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -- Cheers, --MarkM -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/f4fb24e4/attachment-0001.html>
On Feb 19, 2015, at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote:
Half a million times the following meta-exchange happened on es-discuss:
- if an attacker modifies Object.prototype, then you're doomed in all sorts of ways
- Don't let anyone modify it. Just do Object.freeze(Object.prototype)!
Depending on your goals you could use Object.seal. It prevents new properties from being added, but allows you to modify existing properties. From there you could selectively re-define the existing properties with Object.defineProperty and set writable:false.
Although I wouldn’t trust the browser anyway and verify everything server side.
> On Feb 19, 2015, at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote: > > Hi, > > Half a million times the following meta-exchange happened on es-discuss: > - if an attacker modifies Object.prototype, then you're doomed in all sorts of ways > - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! Depending on your goals you could use Object.seal. It prevents new properties from being added, but allows you to modify existing properties. From there you could selectively re-define the existing properties with Object.defineProperty and set writable:false. Although I wouldn’t trust the browser anyway and verify everything server side. Luke
uhm ... have I forgotten a delete
or should I have set {value: Object.prototype[name], writable: false, configurable: false}
instead ? (enumerable should be
preserved as false too)
Yep, actually you got me there, this is a light side effect since usually
nobody redefines the Object.prototype
, but good to know, I could have
fallen hard there.
uhm ... have I forgotten a `delete` or should I have set `{value: Object.prototype[name], writable: false, configurable: false}` instead ? (enumerable should be preserved as false too) Yep, actually you got me there, this is a light side effect since usually nobody redefines the `Object.prototype`, but good to know, I could have fallen hard there. Cheers On Thu, Feb 19, 2015 at 6:06 PM, Mark S. Miller <erights at google.com> wrote: > > > On Thu, Feb 19, 2015 at 9:54 AM, Andrea Giammarchi < > andrea.giammarchi at gmail.com> wrote: > >> Just as workaround, if you really need that much to freeze the >> `Object.prototype`, you could: >> >> ```js >> Object >> .getOwnPropertyNames(Object.prototype) >> .filter((name) => !/^constructor|toString|valueIOf$/.test(name)) >> .forEach((name) => Object.defineProperty( >> Object.prototype, >> name, >> {value: Object.prototype[name]} >> )) >> > > > Your defineProperty call above has no effect. When doing a defineProperty > on an existing property, recall that omitting attributes means that the > setting of these attributes should not be changed. Omitted attributes only > default to false when the property does not already exist. > > Interesting that I've seen this bug several times now, by several > different authors. Apparently, it is an unanticipated footgun in the ES5 > reflection API. > > > >> ; >> Object.preventExtensions(Object.prototype); >> ``` >> >> You can eventually fix those 3 properties somehow via accessors. >> >> Not ideal, but it should hopefully make your project work (at least) >> >> Best Regards >> >> >> On Thu, Feb 19, 2015 at 5:23 PM, David Bruant <bruant.d at gmail.com> wrote: >> >>> Hi, >>> >>> Half a million times the following meta-exchange happened on es-discuss: >>> - if an attacker modifies Object.prototype, then you're doomed in all >>> sorts of ways >>> - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! >>> >>> I've done it on client-side projects with reasonable success. I've just >>> tried on a Node project and lots of dependencies started throwing errors. >>> (I imagine the difference is that in Node, it's easy to create projects >>> with a big tree of dependencies which I haven't done too much on the client >>> side). >>> >>> I tracked down a few of these errors and they all seem to relate to the >>> override mistake [1]. >>> * In jsdom [2], trying to add a "constructor" property to an object >>> fails because Object.prototype.constructor is configurable: false, >>> writable: false >>> * in tough-cookie [3] (which is a dependency of the popular 'request' >>> module), trying to set Cookie.prototype.toString fails because >>> Object.prototype.toString is configurable: false, writable: false >>> >>> Arguably, they could use Object.defineProperty, but they won't because >>> it's less natural and it'd be absurd to try to fix npm. The >>> Cookie.prototype.toString case is interesting. Of all the methods being >>> added, only toString causes a problem. Using Object.defineProperty for this >>> one would be an awkward inconsistency. >>> >>> >>> So, we're in a state where no module needs to modify Object.prototype, >>> but I cannot freeze it because the override mistake makes throw any script >>> that tries to set a toString property to an object. >>> Because of the override mistake, either I have to let Object.prototype >>> mutable (depite no module needing it to be mutable) or freeze it first hand >>> and not use popular modules like jsdom or request. >>> >>> It's obviously possible to replace all built-in props by accessors [4], >>> of course, but this is a bit ridiculous. >>> Can the override mistake be fixed? I imagine no web compat issues would >>> occur since this change is about throwing less errors. >>> >>> David >>> >>> [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ >>> override_mistake >>> [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 >>> 1aff1db291/lib/jsdom/utils.js#L65-L95 >>> [3] https://github.com/goinstant/tough-cookie/blob/ >>> c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 >>> [4] https://github.com/rwaldron/tc39-notes/blob/ >>> c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- >>> 25.md#fix-override-mistake-aka-the-can-put-check >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > > > -- > Cheers, > --MarkM > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/15398a81/attachment.html>
On Thu, Feb 19, 2015 at 10:14 AM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:
uhm ... have I forgotten a
delete
or should I have set{value: Object.prototype[name], writable: false, configurable: false}
instead ? (enumerable should be preserved as false too)
Either would work, but I would do the second. The first technique is not idempotent but the second is. Deleting will fail a second time, but setting a property to its current settings works fine.
On Thu, Feb 19, 2015 at 10:14 AM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote: > uhm ... have I forgotten a `delete` or should I have set `{value: Object.prototype[name], > writable: false, configurable: false}` instead ? (enumerable should be > preserved as false too) > Either would work, but I would do the second. The first technique is not idempotent but the second is. Deleting will fail a second time, but setting a property to its current settings works fine. > > Yep, actually you got me there, this is a light side effect since usually > nobody redefines the `Object.prototype`, but good to know, I could have > fallen hard there. > > Cheers > > On Thu, Feb 19, 2015 at 6:06 PM, Mark S. Miller <erights at google.com> > wrote: > >> >> >> On Thu, Feb 19, 2015 at 9:54 AM, Andrea Giammarchi < >> andrea.giammarchi at gmail.com> wrote: >> >>> Just as workaround, if you really need that much to freeze the >>> `Object.prototype`, you could: >>> >>> ```js >>> Object >>> .getOwnPropertyNames(Object.prototype) >>> .filter((name) => !/^constructor|toString|valueIOf$/.test(name)) >>> .forEach((name) => Object.defineProperty( >>> Object.prototype, >>> name, >>> {value: Object.prototype[name]} >>> )) >>> >> >> >> Your defineProperty call above has no effect. When doing a defineProperty >> on an existing property, recall that omitting attributes means that the >> setting of these attributes should not be changed. Omitted attributes only >> default to false when the property does not already exist. >> >> Interesting that I've seen this bug several times now, by several >> different authors. Apparently, it is an unanticipated footgun in the ES5 >> reflection API. >> >> >> >>> ; >>> Object.preventExtensions(Object.prototype); >>> ``` >>> >>> You can eventually fix those 3 properties somehow via accessors. >>> >>> Not ideal, but it should hopefully make your project work (at least) >>> >>> Best Regards >>> >>> >>> On Thu, Feb 19, 2015 at 5:23 PM, David Bruant <bruant.d at gmail.com> >>> wrote: >>> >>>> Hi, >>>> >>>> Half a million times the following meta-exchange happened on es-discuss: >>>> - if an attacker modifies Object.prototype, then you're doomed in all >>>> sorts of ways >>>> - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! >>>> >>>> I've done it on client-side projects with reasonable success. I've just >>>> tried on a Node project and lots of dependencies started throwing errors. >>>> (I imagine the difference is that in Node, it's easy to create projects >>>> with a big tree of dependencies which I haven't done too much on the client >>>> side). >>>> >>>> I tracked down a few of these errors and they all seem to relate to the >>>> override mistake [1]. >>>> * In jsdom [2], trying to add a "constructor" property to an object >>>> fails because Object.prototype.constructor is configurable: false, >>>> writable: false >>>> * in tough-cookie [3] (which is a dependency of the popular 'request' >>>> module), trying to set Cookie.prototype.toString fails because >>>> Object.prototype.toString is configurable: false, writable: false >>>> >>>> Arguably, they could use Object.defineProperty, but they won't because >>>> it's less natural and it'd be absurd to try to fix npm. The >>>> Cookie.prototype.toString case is interesting. Of all the methods being >>>> added, only toString causes a problem. Using Object.defineProperty for this >>>> one would be an awkward inconsistency. >>>> >>>> >>>> So, we're in a state where no module needs to modify Object.prototype, >>>> but I cannot freeze it because the override mistake makes throw any script >>>> that tries to set a toString property to an object. >>>> Because of the override mistake, either I have to let Object.prototype >>>> mutable (depite no module needing it to be mutable) or freeze it first hand >>>> and not use popular modules like jsdom or request. >>>> >>>> It's obviously possible to replace all built-in props by accessors [4], >>>> of course, but this is a bit ridiculous. >>>> Can the override mistake be fixed? I imagine no web compat issues would >>>> occur since this change is about throwing less errors. >>>> >>>> David >>>> >>>> [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ >>>> override_mistake >>>> [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 >>>> 1aff1db291/lib/jsdom/utils.js#L65-L95 >>>> [3] https://github.com/goinstant/tough-cookie/blob/ >>>> c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 >>>> [4] https://github.com/rwaldron/tc39-notes/blob/ >>>> c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- >>>> 25.md#fix-override-mistake-aka-the-can-put-check >>>> _______________________________________________ >>>> es-discuss mailing list >>>> es-discuss at mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> >> >> -- >> Cheers, >> --MarkM >> > > -- Cheers, --MarkM -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/6ed1d3cc/attachment-0001.html>
this, and the fact descriptors suffer inheritance which for 3 boolean properties or a method are absolutely not helpful and make the env doomed by
Object.prototype.writable = true
shenanigans.
Umm, those solutions are in opposition. If you seal-freeze-scotch-tape Object.prototype up, no-one's going to add get
s, set
s and writable
s to it. Taking inheritance into account in defineProperty won’t then be a problem.
> this, and the fact descriptors suffer inheritance which for 3 boolean properties or a method are absolutely not helpful and make the env doomed by `Object.prototype.writable = true` shenanigans. Umm, those solutions are in opposition. If you seal-freeze-scotch-tape Object.prototype up, no-one's going to add `get`s, `set`s and `writable`s to it. Taking inheritance into account in defineProperty won’t then be a problem. A. On Feb 19, 2015, at 19:58, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote: > this, and the fact descriptors suffer inheritance which for 3 boolean properties or a method are absolutely not helpful and make the env doomed by `Object.prototype.writable = true` shenanigans. > > Yes, I'd personally +1 all these fixes that made these ES5 features not the easiest one to play with > > On Thu, Feb 19, 2015 at 5:41 PM, Mark S. Miller <erights at google.com> wrote: > On Thu, Feb 19, 2015 at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote: > Hi, > > Half a million times the following meta-exchange happened on es-discuss: > - if an attacker modifies Object.prototype, then you're doomed in all sorts of ways > - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! > > I've done it on client-side projects with reasonable success. I've just tried on a Node project and lots of dependencies started throwing errors. (I imagine the difference is that in Node, it's easy to create projects with a big tree of dependencies which I haven't done too much on the client side). > > I tracked down a few of these errors and they all seem to relate to the override mistake [1]. > * In jsdom [2], trying to add a "constructor" property to an object fails because Object.prototype.constructor is configurable: false, writable: false > * in tough-cookie [3] (which is a dependency of the popular 'request' module), trying to set Cookie.prototype.toString fails because Object.prototype.toString is configurable: false, writable: false > > Arguably, they could use Object.defineProperty, but they won't because it's less natural and it'd be absurd to try to fix npm. The Cookie.prototype.toString case is interesting. Of all the methods being added, only toString causes a problem. Using Object.defineProperty for this one would be an awkward inconsistency. > > > So, we're in a state where no module needs to modify Object.prototype, but I cannot freeze it because the override mistake makes throw any script that tries to set a toString property to an object. > Because of the override mistake, either I have to let Object.prototype mutable (depite no module needing it to be mutable) or freeze it first hand and not use popular modules like jsdom or request. > > It's obviously possible to replace all built-in props by accessors [4], of course, but this is a bit ridiculous. > > It is indeed ridiculous. Not fixing this in the ES5 timeframe was my single biggest failure and disappointment as a member of TC39. > > For reference, Caja's implementation of the technique described in [4] is at > > https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#278 > > As it states, our term for freezing an object so that it does not provoke this problem is "tamper proofing". > > > Can the override mistake be fixed? I imagine no web compat issues would occur since this change is about throwing less errors. > > There was a time when some of the browsers did not suffer from the override mistake, and in so doing, were technically out of conformance with the ES5 spec. During this window, it was clearly still web compatible to fix the override mistake. It was during this window that I raised the issue and argued that it be fixed. I brought this up in meetings several times and never made any progress. Once all browsers suffered equally from the override mistake, it was no longer *clearly* web compatible to fix it, so I gave up and focussed on other things instead. > > However, I agree with your suspicion that it actually would still be web compatible to fix this. Unfortunately, the only way to find out at this point is for a browser to try deploying without the override mistake. I don't have much hope. > > Instead, I suggest you promote tamper proofing to those audiences to which you currently promote freezing. Though the need for it is indeed ridiculous, it actually works rather well. We've been using it successfully for many years now. > > > > > David > > [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_override_mistake > [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d025341aff1db291/lib/jsdom/utils.js#L65-L95 > [3] https://github.com/goinstant/tough-cookie/blob/c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 > [4] https://github.com/rwaldron/tc39-notes/blob/c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july-25.md#fix-override-mistake-aka-the-can-put-check > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > > -- > Cheers, > --MarkM > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/96126e16/attachment.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 4786 bytes Desc: not available URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/96126e16/attachment.p7s>
Yeah, beside the fact whenever you freeze something, and you create a module, or a library, or whatever, you don't know what you are freezing up.
Since priority is arbitrary, if script A sets stuff before script B then you are done.
Also, I use Object.prototype without causing any sort of problems/error since years now, nobody complained, but an Object.freeze upfront would screw the library anyway.
Trust what you load in and avoid XSS from users as much as you can .... you have your problem fixed for most of the cases (and the current state of JS)
Yeah, beside the fact whenever you freeze something, and you create a module, or a library, or whatever, you don't know what you are freezing up. Since priority is arbitrary, if script A sets stuff before script B then you are done. Also, I use Object.prototype without causing any sort of problems/error since years now, nobody complained, but an Object.freeze upfront would screw the library anyway. Trust what you load in and avoid XSS from users as much as you can .... you have your problem fixed for most of the cases (and the current state of JS) Best Regards On Thu, Feb 19, 2015 at 6:50 PM, Andri Möll <andri at dot.ee> wrote: > this, and the fact descriptors suffer inheritance which for 3 boolean > properties or a method are absolutely not helpful and make the env doomed > by `Object.prototype.writable = true` shenanigans. > > > Umm, those solutions are in opposition. If you seal-freeze-scotch-tape > Object.prototype up, no-one's going to add `get`s, `set`s and `writable`s > to it. Taking inheritance into account in defineProperty won’t then be a > problem. > > A. > > On Feb 19, 2015, at 19:58, Andrea Giammarchi <andrea.giammarchi at gmail.com> > wrote: > > this, and the fact descriptors suffer inheritance which for 3 boolean > properties or a method are absolutely not helpful and make the env doomed > by `Object.prototype.writable = true` shenanigans. > > Yes, I'd personally +1 all these fixes that made these ES5 features not > the easiest one to play with > > On Thu, Feb 19, 2015 at 5:41 PM, Mark S. Miller <erights at google.com> > wrote: > >> On Thu, Feb 19, 2015 at 9:23 AM, David Bruant <bruant.d at gmail.com> wrote: >> >>> Hi, >>> >>> Half a million times the following meta-exchange happened on es-discuss: >>> - if an attacker modifies Object.prototype, then you're doomed in all >>> sorts of ways >>> - Don't let anyone modify it. Just do Object.freeze(Object.prototype)! >>> >>> I've done it on client-side projects with reasonable success. I've just >>> tried on a Node project and lots of dependencies started throwing errors. >>> (I imagine the difference is that in Node, it's easy to create projects >>> with a big tree of dependencies which I haven't done too much on the client >>> side). >>> >>> I tracked down a few of these errors and they all seem to relate to the >>> override mistake [1]. >>> * In jsdom [2], trying to add a "constructor" property to an object >>> fails because Object.prototype.constructor is configurable: false, >>> writable: false >>> * in tough-cookie [3] (which is a dependency of the popular 'request' >>> module), trying to set Cookie.prototype.toString fails because >>> Object.prototype.toString is configurable: false, writable: false >>> >>> Arguably, they could use Object.defineProperty, but they won't because >>> it's less natural and it'd be absurd to try to fix npm. The >>> Cookie.prototype.toString case is interesting. Of all the methods being >>> added, only toString causes a problem. Using Object.defineProperty for this >>> one would be an awkward inconsistency. >>> >>> >>> So, we're in a state where no module needs to modify Object.prototype, >>> but I cannot freeze it because the override mistake makes throw any script >>> that tries to set a toString property to an object. >>> Because of the override mistake, either I have to let Object.prototype >>> mutable (depite no module needing it to be mutable) or freeze it first hand >>> and not use popular modules like jsdom or request. >>> >>> It's obviously possible to replace all built-in props by accessors [4], >>> of course, but this is a bit ridiculous. >>> >> >> It is indeed ridiculous. Not fixing this in the ES5 timeframe was my >> single biggest failure and disappointment as a member of TC39. >> >> For reference, Caja's implementation of the technique described in [4] is >> at >> >> >> https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#278 >> >> As it states, our term for freezing an object so that it does not provoke >> this problem is "tamper proofing". >> >> >> >>> Can the override mistake be fixed? I imagine no web compat issues would >>> occur since this change is about throwing less errors. >>> >> >> There was a time when some of the browsers did not suffer from the >> override mistake, and in so doing, were technically out of conformance with >> the ES5 spec. During this window, it was clearly still web compatible to >> fix the override mistake. It was during this window that I raised the issue >> and argued that it be fixed. I brought this up in meetings several times >> and never made any progress. Once all browsers suffered equally from the >> override mistake, it was no longer *clearly* web compatible to fix it, so I >> gave up and focussed on other things instead. >> >> However, I agree with your suspicion that it actually would still be web >> compatible to fix this. Unfortunately, the only way to find out at this >> point is for a browser to try deploying without the override mistake. I >> don't have much hope. >> >> Instead, I suggest you promote tamper proofing to those audiences to >> which you currently promote freezing. Though the need for it is indeed >> ridiculous, it actually works rather well. We've been using it successfully >> for many years now. >> >> >> >> >>> >>> David >>> >>> [1] http://wiki.ecmascript.org/doku.php?id=strawman:fixing_ >>> override_mistake >>> [2] https://github.com/tmpvar/jsdom/blob/6c5fe5be8cd01e0b4e91fa96d02534 >>> 1aff1db291/lib/jsdom/utils.js#L65-L95 >>> [3] https://github.com/goinstant/tough-cookie/blob/ >>> c66bebadd634f4ff5d8a06519f9e0e4744986ab8/lib/cookie.js#L694 >>> [4] https://github.com/rwaldron/tc39-notes/blob/ >>> c61f48cea5f2339a1ec65ca89827c8cff170779b/es6/2012-07/july- >>> 25.md#fix-override-mistake-aka-the-can-put-check >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> >> >> >> -- >> Cheers, >> --MarkM >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150219/3e0ecd2a/attachment-0001.html>
Half a million times the following meta-exchange happened on es-discuss:
I've done it on client-side projects with reasonable success. I've just tried on a Node project and lots of dependencies started throwing errors. (I imagine the difference is that in Node, it's easy to create projects with a big tree of dependencies which I haven't done too much on the client side).
I tracked down a few of these errors and they all seem to relate to the override mistake.
Arguably, they could use Object.defineProperty, but they won't because it's less natural and it'd be absurd to try to fix npm. The Cookie.prototype.toString case is interesting. Of all the methods being added, only toString causes a problem. Using Object.defineProperty for this one would be an awkward inconsistency.
So, we're in a state where no module needs to modify Object.prototype, but I cannot freeze it because the override mistake makes throw any script that tries to set a toString property to an object. Because of the override mistake, either I have to let Object.prototype mutable (depite no module needing it to be mutable) or freeze it first hand and not use popular modules like jsdom or request.
It's obviously possible to replace all built-in props by accessors, of course, but this is a bit ridiculous. Can the override mistake be fixed? I imagine no web compat issues would occur since this change is about throwing less errors.