Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On 9 November 2011 00:16, Mark S. Miller erig...@google.com wrote: On Tue, Nov 8, 2011 at 12:50 PM, Andreas Rossberg rossb...@google.com wrote: On 8 November 2011 20:46, Mark S. Miller erig...@google.com wrote: Nevertheless, I see your point. Many defensive ES5 abstractions will be less defensive than this. If I understand you correctly, your point is specifically about the [[Call]] and [[Construct]] traps. Yes. Existing code has no reason to bother making functions non-extensible if all it does is calling them. Proxy.attach fundamentally breaks that (so far correct, AFAICT) assumption. I think we're agreeing on the operational point -- that much defensive code won't bother to freeze such functions. But for clarity, I must correct your no reason. The reason is one of the oldest software engineering best practices: Say What You Mean. Perhaps a clearer statement is Mean Only What You Say. The it in your above sentence presumes a non-local whole program analysis which violates this rule, and is in any case inapplicable to libraries. To keep what the program means in sync with what it seems to mean, we need to avoid introducing unexpressed communication channels. Or, put another way, unexpressed shared mutable locations. If Alice provides object C to both B and D, the only ways in which this should enable further communication between B and D (beyond that which they may have already had) should be according to the expressed behavior of C. For example, if the expressed behavior of C is completely stateless, then the fact that B and D both share a reference to C should not enable any additional communications/interaction/influence between B and D. These constraints are useful for much beyond security. If you wish to program in a mostly functional style, you'd like the deviations from functional style to only be where you've made a purposeful choice. When debugging, you need to figure out: How did the bad symptom happen? If you can bound the possible causes, by reasoning in terms of the program's intended behavior, your detective work is much easier. Agreed with everything you say. But I suppose there are two levels of concern: protecting your own abstractions, and not providing security loopholes that others can exploit to harm third parties. Given how hostile JS is towards encouraging the latter, I would expect that a significant amount of code exists that only cares about the former, which I think is a valid concern on its own. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On Tue, Nov 8, 2011 at 4:58 PM, Tom Van Cutsem tomvc...@gmail.com wrote: Perhaps we should be more conservative here, without necessarily backing away from the whole Proxy.attach idea? Disallowing attaching to functions with your own call/construct traps would be the minimal restriction, I think. But maybe there is something cleaner. I wonder if chaperones, as implemented in Racket, would be of help here. To my understanding, a chaperone is a proxy that is very restricted in its actions, specifically: when intercepting a function call, a chaperone is only allowed to throw an exception, return the original value, or a chaperone for the original value (racketeers on this list should correct me where needed). Chaperones would still be powerful enough to express data binding: firing an update event as a side-effect does not require changing the arguments or return values of wrapped functions. However, at this point I'm not yet sufficiently familiar with chaperones to see how they can be adapted into our Proxy framework. That's a very accurate summary. I agree with Andreas that this is a significant risk for Proxy.attach. ES in the wild has few enough invariants that we should be very wary of breaking the ones we've got. However, the direct proxy proposal is already enforcing some invariants -- the proxy must produce === values to the underlying object for frozen properties. Could we just reuse this mechanism for the [[Call]] and [[Construct]] behavior of functions in the cases Andreas brings up for Proxy.attach (if we decide that we want it)? The idea of chaperones would be then relaxing this invariant slightly, to allow frozen properties to produce proxies for the underlying property value, instead of just something === to it. This makes proxies more expressive in some cases, without reducing the invariants we can rely on. -- sam th sa...@ccs.neu.edu ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
Le 08/11/2011 14:26, Andreas Rossberg a écrit : On 3 November 2011 23:55, Mark S. Miller erig...@google.com wrote: If I understood Mark correctly, the features needed for SES are already part of ES.5 and are shipping in browsers (and hence don't bear upon future features). Did I misunderstand? These do bear on future features in three ways: 1) Future features could easily destroy all the security gains that ES5 achieved. I'm still trying to grasp the implications of the recent direct proxy proposal in this respect -- more precisely, its startTrapping functionality. Just as a reminder, startTrapping really is not necessary to direct proxies (Proxy.for) and should both should be considered independently (even though they are on the same strawman) It seems to me that the ability to attach to a function, in particular, invalidates all current security guarantees, since it gives a whole new way of completely redefining any random function _in place_ by simply turning it into a function proxy. That is, even if that function is given by a non-writable binding or property! Given that direct proxies are not in a position to violate any of the *non-configurability or non-extensibility constraints* of their wrapped target, it should be safe to replace an existing normal object by a direct proxy wrapping that object. My understanding is that regarding the issue you mention, you cannot do more with startTrapping than redefining built-ins by (re)setting a property. Though, I agree about the non-writable binding. Something should be added about that. And it seems so much safer to prevent start trapping the global object because things could get nasty otherwise. To achieve the effect of today's Object.{seal,freeze}, you hence also would have to make _every_ of the object's properties non-attachable. That is certainly possible, but seems considerably more fragile.And it still breaks the security of pre-existing SES code. IOW, I sense a security hazard. I agree that there is a hazard but I am not sure it is that much bigger than the opportunity for an attacker to redefine built-ins. This opportunity exists since the origin of JavaScript (so before ES5 and SES). I also wonder about the effect that turning an (ordinary) object into a proxy would have on the visibility of private names. If one of the original methods accesses a private property on `this', then, according to the private names proposal, the handler only gets to see the .public property of that name. But can't this still leak information? The handler cannot use it to _read_ the existing property data, but it will still receive all future _writes_ to it. Am I missing something? I don't think you are. I think you are right. As said, the startTrapping proposal is controversial. Proxies are still very new. I'm not sure it's wise to add the startTrapping. If we ever realize that this is really needed, i don't think there is a problem with adding it in a later ECMAScript version. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On Tue, Nov 8, 2011 at 5:26 AM, Andreas Rossberg rossb...@google.comwrote: On 3 November 2011 23:55, Mark S. Miller erig...@google.com wrote: If I understood Mark correctly, the features needed for SES are already part of ES.5 and are shipping in browsers (and hence don't bear upon future features). Did I misunderstand? These do bear on future features in three ways: 1) Future features could easily destroy all the security gains that ES5 achieved. I'm still trying to grasp the implications of the recent direct proxy proposal in this respect -- more precisely, its startTrapping functionality. It seems to me that the ability to attach to a function, in particular, invalidates all current security guarantees, since it gives a whole new way of completely redefining any random function _in place_ by simply turning it into a function proxy. That is, even if that function is given by a non-writable binding or property! To achieve the effect of today's Object.{seal,freeze}, you hence also would have to make _every_ of the object's properties non-attachable. That is certainly possible, but seems considerably more fragile. And it still breaks the security of pre-existing SES code. IOW, I sense a security hazard. Hi Andreas, thanks for starting a discussion on this. I agree that there is a huge danger here. There is another approach to so-called data binding (treat it like an optimization of polling) that cannot cause any loss of security (if equivalence to polling really is maintained). Altogether, from a security pov, we'd certainly be better off without Proxy.attach. The reason Proxy.attach may not be fatal is that it only allows attachment to extensible objects. Our hypothesis is that any ES5 object that is interested in defending itself has already made itself non-extensible. This is why we must key this off of non-extensibility, rather than introducing a new orthogonal bit -- to avoid breaching the defenses of those ES5 era objects that tried to defend themselves. ES3 era objects could not defend themselves, so attaching to them cannot violate any of their valid assumptions -- to a first approximation, they could not validly assume anything. I also wonder about the effect that turning an (ordinary) object into a proxy would have on the visibility of private names. If one of the original methods accesses a private property on `this', then, according to the private names proposal, the handler only gets to see the .public property of that name. But can't this still leak information? The handler cannot use it to _read_ the existing property data, but it will still receive all future _writes_ to it. Am I missing something? Only the defensiveness points above. Regarding data binding, we should also see if the non-dangerous poll-optimization-equivalence can meet our needs instead, in which case we probably don't need Proxy.attach. /Andreas -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On 8 November 2011 18:47, David Bruant bruan...@gmail.com wrote: Given that direct proxies are not in a position to violate any of the *non-configurability or non-extensibility constraints* of their wrapped target, it should be safe to replace an existing normal object by a direct proxy wrapping that object. My understanding is that regarding the issue you mention, you cannot do more with startTrapping than redefining built-ins by (re)setting a property. That may be true for plain objects, but I think the situation is quite different for functions, because there is no equivalent to non-configurable for the [[Call]] and [[Construct]] properties. On 8 November 2011 19:13, Mark S. Miller erig...@google.com wrote: The reason Proxy.attach may not be fatal is that it only allows attachment to extensible objects. Our hypothesis is that any ES5 object that is interested in defending itself has already made itself non-extensible. This is why we must key this off of non-extensibility, rather than introducing a new orthogonal bit -- to avoid breaching the defenses of those ES5 era objects that tried to defend themselves. I don't think that addresses the issue I was describing. The problem is: the object itself can all be frozen, non-extensible, non-attachable just fine, but that doesn't achieve much by itself anymore because an attacker can still attach to each individual method, since they are entirely separate objects! So instead of just freezing an object, you _additionally_ would have to make all its _individual methods_ non-attachable (by whatever means). AFAICS, that affects assumptions of existing ES5 code quite severely. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On 8 November 2011 20:29, Andreas Rossberg rossb...@google.com wrote: On 8 November 2011 18:47, David Bruant bruan...@gmail.com wrote: Given that direct proxies are not in a position to violate any of the *non-configurability or non-extensibility constraints* of their wrapped target, it should be safe to replace an existing normal object by a direct proxy wrapping that object. My understanding is that regarding the issue you mention, you cannot do more with startTrapping than redefining built-ins by (re)setting a property. That may be true for plain objects, but I think the situation is quite different for functions, because there is no equivalent to non-configurable for the [[Call]] and [[Construct]] properties. BTW, a similar issue applies to getters and setters: even if a property is non-configurable, as long as it is defined by accessors an attacker could attach to the underlying JS functions and thereby essentially redefine the property without actually modifying it. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On Tue, Nov 8, 2011 at 11:29 AM, Andreas Rossberg rossb...@google.comwrote: On 8 November 2011 19:13, Mark S. Miller erig...@google.com wrote: The reason Proxy.attach may not be fatal is that it only allows attachment to extensible objects. Our hypothesis is that any ES5 object that is interested in defending itself has already made itself non-extensible. This is why we must key this off of non-extensibility, rather than introducing a new orthogonal bit -- to avoid breaching the defenses of those ES5 era objects that tried to defend themselves. I don't think that addresses the issue I was describing. The problem is: the object itself can all be frozen, non-extensible, non-attachable just fine, but that doesn't achieve much by itself anymore because an attacker can still attach to each individual method, since they are entirely separate objects! So instead of just freezing an object, you _additionally_ would have to make all its _individual methods_ non-attachable (by whatever means). AFAICS, that affects assumptions of existing ES5 code quite severely. In general, for an object to be defensive, much of the surface reachable from it by transitive prototype and reflective property traversal should usually be frozen, and at least non-extensible. This is possible to express in ES5 http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#623, but inconvenient and expensive. That's why I have been advocating better defensive abstractions for ES6: const functions, const classes, traitsjs or its syntactic derivatives, etc. Nevertheless, I see your point. Many defensive ES5 abstractions will be less defensive than this. If I understand you correctly, your point is specifically about the [[Call]] and [[Construct]] traps. Perhaps we should be more conservative here, without necessarily backing away from the whole Proxy.attach idea? -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On 8 November 2011 20:46, Mark S. Miller erig...@google.com wrote: In general, for an object to be defensive, much of the surface reachable from it by transitive prototype and reflective property traversal should usually be frozen, and at least non-extensible. This is possible to express in ES5 http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#623, but inconvenient and expensive. That's why I have been advocating better defensive abstractions for ES6: const functions, const classes, traitsjs or its syntactic derivatives, etc. Nevertheless, I see your point. Many defensive ES5 abstractions will be less defensive than this. If I understand you correctly, your point is specifically about the [[Call]] and [[Construct]] traps. Yes. Existing code has no reason to bother making functions non-extensible if all it does is calling them. Proxy.attach fundamentally breaks that (so far correct, AFAICT) assumption. Perhaps we should be more conservative here, without necessarily backing away from the whole Proxy.attach idea? Disallowing attaching to functions with your own call/construct traps would be the minimal restriction, I think. But maybe there is something cleaner. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Security and direct proxies (Was: Re: Lecture series on SES and capability-based security by Mark Miller)
On Tue, Nov 8, 2011 at 12:50 PM, Andreas Rossberg rossb...@google.comwrote: On 8 November 2011 20:46, Mark S. Miller erig...@google.com wrote: Nevertheless, I see your point. Many defensive ES5 abstractions will be less defensive than this. If I understand you correctly, your point is specifically about the [[Call]] and [[Construct]] traps. Yes. Existing code has no reason to bother making functions non-extensible if all it does is calling them. Proxy.attach fundamentally breaks that (so far correct, AFAICT) assumption. I think we're agreeing on the operational point -- that much defensive code won't bother to freeze such functions. But for clarity, I must correct your no reason. The reason is one of the oldest software engineering best practices: Say What You Mean. Perhaps a clearer statement is Mean Only What You Say. The it in your above sentence presumes a non-local whole program analysis which violates this rule, and is in any case inapplicable to libraries. To keep what the program means in sync with what it seems to mean, we need to avoid introducing unexpressed communication channels. Or, put another way, unexpressed shared mutable locations. If Alice provides object C to both B and D, the only ways in which this should enable further communication between B and D (beyond that which they may have already had) should be according to the expressed behavior of C. For example, if the expressed behavior of C is completely stateless, then the fact that B and D both share a reference to C should not enable any additional communications/interaction/influence between B and D. These constraints are useful for much beyond security. If you wish to program in a mostly functional style, you'd like the deviations from functional style to only be where you've made a purposeful choice. When debugging, you need to figure out: How did the bad symptom happen? If you can bound the possible causes, by reasoning in terms of the program's intended behavior, your detective work is much easier. A program should not only work. It should also appear to work. --Carl Hewitt. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
Perhaps __proto__ should not be writeable in use strict? That's a great idea! This never occurred to me, and I have not heard anyone suggest this. Thanks! Doesn't work. obj[(function(__){return __ + proto + __})(__)] Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Tue, Nov 8, 2011 at 3:33 PM, David Herman dher...@mozilla.com wrote: Perhaps __proto__ should not be writeable in use strict? That's a great idea! This never occurred to me, and I have not heard anyone suggest this. Thanks! Doesn't work. obj[(function(__){return __ + proto + __})(__)] If the [ above is a strict [, it should not be able to address __proto__, regardless of whether the __proto__ is computed or not. Or if we intend only to suppress writing, then obj[(function(__){return __ + proto + __})(__)] = {} should still fail if the [ above is in strict code. Dave -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Tue, Nov 8, 2011 at 3:46 PM, Mark S. Miller erig...@google.com wrote: On Tue, Nov 8, 2011 at 3:33 PM, David Herman dher...@mozilla.com wrote: Perhaps __proto__ should not be writeable in use strict? That's a great idea! This never occurred to me, and I have not heard anyone suggest this. Thanks! Doesn't work. obj[(function(__){return __ + proto + __})(__)] If the [ above is a strict [, it should not be able to address __proto__, regardless of whether the __proto__ is computed or not. Or if we intend only to suppress writing, then obj[(function(__){return __ + proto + __})(__)] = {} should still fail if the [ above is in strict code. Sorry, it should not fail. It should simply create a normal property that happens to be named __proto__. Likewise, your first example should simply address such a normal property. Then JSON would again be an almost-subset of ES5/strict, modulo \u2028 and \u2029. Dave -- Cheers, --MarkM -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
http://www.google.com/support/forum/p/Google+Docs/thread?tid=0cd4a00bd4aef9e4 But yes. Because the difference would be silent, I'm skeptical too. On Tue, Nov 8, 2011 at 8:23 PM, David Herman dher...@mozilla.com wrote: And another silent semantic change? I wouldn't be so quick to do that. And that's not the direction we were going for __proto__ in the last f2f. I *wish* __proto__ were just treated as another normal property. And I'd like for us to work towards a future where that's the case. I'm just skeptical we can do it by cramming it into strict mode. Dave On Nov 8, 2011, at 3:50 PM, Mark S. Miller wrote: On Tue, Nov 8, 2011 at 3:46 PM, Mark S. Miller erig...@google.com wrote: On Tue, Nov 8, 2011 at 3:33 PM, David Herman dher...@mozilla.com wrote: Perhaps __proto__ should not be writeable in use strict? That's a great idea! This never occurred to me, and I have not heard anyone suggest this. Thanks! Doesn't work. obj[(function(__){return __ + proto + __})(__)] If the [ above is a strict [, it should not be able to address __proto__, regardless of whether the __proto__ is computed or not. Or if we intend only to suppress writing, then obj[(function(__){return __ + proto + __})(__)] = {} should still fail if the [ above is in strict code. Sorry, it should not fail. It should simply create a normal property that happens to be named __proto__. Likewise, your first example should simply address such a normal property. Then JSON would again be an almost-subset of ES5/strict, modulo \u2028 and \u2029. Dave -- Cheers, --MarkM -- Cheers, --MarkM -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
One more thought: people are already avoiding use strict; because it bites back: * concatenation with non-strict code and under-testing, but let's hope we are past this now; * performance dinged a bit by strict mode, or at least non-strict calling strict and vice versa. We should try to avoid taking away the forbidden fruit prematurely. In particular since ES6 is based on ES5 strict. When | is out and well-deployed, maybe. No predictable schedule for when we could actually hope to remove __proto__. /be On Nov 8, 2011, at 8:57 PM, Mark S. Miller wrote: http://www.google.com/support/forum/p/Google+Docs/thread?tid=0cd4a00bd4aef9e4 But yes. Because the difference would be silent, I'm skeptical too. On Tue, Nov 8, 2011 at 8:23 PM, David Herman dher...@mozilla.com wrote: And another silent semantic change? I wouldn't be so quick to do that. And that's not the direction we were going for __proto__ in the last f2f. I *wish* __proto__ were just treated as another normal property. And I'd like for us to work towards a future where that's the case. I'm just skeptical we can do it by cramming it into strict mode. Dave On Nov 8, 2011, at 3:50 PM, Mark S. Miller wrote: On Tue, Nov 8, 2011 at 3:46 PM, Mark S. Miller erig...@google.com wrote: On Tue, Nov 8, 2011 at 3:33 PM, David Herman dher...@mozilla.com wrote: Perhaps __proto__ should not be writeable in use strict? That's a great idea! This never occurred to me, and I have not heard anyone suggest this. Thanks! Doesn't work. obj[(function(__){return __ + proto + __})(__)] If the [ above is a strict [, it should not be able to address __proto__, regardless of whether the __proto__ is computed or not. Or if we intend only to suppress writing, then obj[(function(__){return __ + proto + __})(__)] = {} should still fail if the [ above is in strict code. Sorry, it should not fail. It should simply create a normal property that happens to be named __proto__. Likewise, your first example should simply address such a normal property. Then JSON would again be an almost-subset of ES5/strict, modulo \u2028 and \u2029. Dave -- Cheers, --MarkM -- Cheers, --MarkM -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
In .. an ES5/strict environment in which all primordial built-in objects are transitively frozen, .. function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } .. Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? Hm. A favorite pattern that I haven't thought about enough, it seems. My curiosity did cost me some sleep:-| My favorite work around for your constraints is this little shim:-) // dynamic language Object.freeze = function(obj){return obj}; You imply that this is not intended, so I can show it without spoiling the fun. I was surprised that this works. The first solution that came to mind ought to be defeated by your transitively frozen constraint, and it is, in current JS implementations, though not all JS implementations in the wild are there yet - do you feature-detect old engines and issue warnings if they invalidate your base assumptions? The second approach took longer to find but relies on non-standard features (and again, I suspect a bug/interpretation issue). Both ideas are weak, in that they could be blocked by type checks. If you've already seen this puzzle and know the answer, please don't post. If no one else has posted the correct answer in 24 hours, I will. Neither of my approaches seems to be the droid you are looking for, given your no realistic fix remark, so I'm curious what else I've missed. Note that I don't see any realistic way to fix problem #3 in the ES.next language. My point is only that defensive programming is tricky even after you've gotten all the formal properties you need. As ES.next introduces various new abstraction mechanisms, whether classes, enhanced object literals, proxies, modules, or private names, the design of these can either help or hurt those attempting to write defensive abstractions. Any class abstraction that is only useful for making indefensible instances is worse than useless -- it is actively harmful, both to security and to serious software engineering. You also rely on you security base framework being the first to run, and on nobody trying to modify source on load, right? Claus http://clausreinke.github.com/ http://clausreinke.github.com/js-tools/ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Nov 4, 2011, at 8:50 AM, Juan Ignacio Dopazo wrote: On Thu, Nov 3, 2011 at 7:55 PM, Mark S. Miller erig...@google.com wrote: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? So Bob can cheat by extending Array.prototype, right? MarkM said all primordial built-in objects are transitively frozen so Array.prototype is not extensible and Array.prototype.push is not writable... Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 8:14 AM, Claus Reinke claus.rei...@talk21.comwrote: Hm. A favorite pattern that I haven't thought about enough, it seems. My curiosity did cost me some sleep:-| My favorite work around for your constraints is this little shim:-) // dynamic language Object.freeze = function(obj){return obj}; You imply that this is not intended, so I can show it without spoiling the fun. I was surprised that this works. Since the primordials are already frozen, this assignment fails. The first solution that came to mind ought to be defeated by your transitively frozen constraint, and it is, in current JS implementations, though not all JS implementations in the wild are there yet - do you feature-detect old engines and issue warnings if they invalidate your base assumptions? Yes, as shown by http://es-lab.googlecode.com/svn/trunk/src/ses/explicit.html. For example, Firefox 7.0.1 shows Max Severity: Not isolated(4) is not SES-safe. Chrome 16 shows Max Severity: Safe spec violation(1). Firefox Nightly 10.0a1 shows no Max Severity line because it encountered no unrepairable problems. If you do a view source, you'll see the text // This severity is too high for any use other than development. ses.maxAcceptableSeverityName = 'NEW_SYMPTOM'; For production use, depending on you're purpose, you'd probably let the max acceptable severity default, in which case initSES.js will fail quickly as soon as it detects that this platform cannot be made SES-safe. Once initSES.js terminates, ses.ok() indicates whether the max acceptable severity has been exceeded. The severity levels can currently be found at http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#85 We are currently in the process of integrating SES in with the rest of Caja. If you're only targeting SES-safe browsers you can still use initSES.js by itself. Otherwise, if you deploy through Caja, the plan is that Caja will detect whether this is a SES-safe platform, deploy without translation using SES if so, and otherwise fall back to Caja's ES5-to-ES3 translator. The second approach took longer to find but relies on non-standard features (and again, I suspect a bug/interpretation issue). What is your second approach? Both ideas are weak, in that they could be blocked by type checks. How? If you've already seen this puzzle and know the answer, please don't post. If no one else has posted the correct answer in 24 hours, I will. Neither of my approaches seems to be the droid you are looking for, given your no realistic fix remark, so I'm curious what else I've missed. I should take this opportunity to reveal that David Herman found a bug last night with my challenge. Due to a feature of ES3 which ES5.1 preserves, and which I keep forgetting about because it has always seemed only to be annoyance, the attack I had in mind actually fails on an ES5.1 conformant browser. Another reason I missed it is my attack succeeds on Chrome/v8, because it does not implement this feature. Dave found it because FF/SpiderMonkey is ES5.1 conformant in this regard. After he rediscovered the attack, it failed when he tried it on SpiderMonkey, reminding both of us of this annoyance. Perhaps this annoyance really is a feature after all? I asked him to keep quiet about it for the remainder of the 24 hours because I was curious to see what people came up with. Congrats to Dave! Note that I don't see any realistic way to fix problem #3 in the ES.next language. My point is only that defensive programming is tricky even after you've gotten all the formal properties you need. As ES.next introduces various new abstraction mechanisms, whether classes, enhanced object literals, proxies, modules, or private names, the design of these can either help or hurt those attempting to write defensive abstractions. Any class abstraction that is only useful for making indefensible instances is worse than useless -- it is actively harmful, both to security and to serious software engineering. You also rely on you security base framework being the first to run, Yes, absolutely. and on nobody trying to modify source on load, right? I think the answer to this is yes as well, but first I should ask for clarification: source to what? Claus http://clausreinke.github.com/ http://clausreinke.github.com/**js-tools/http://clausreinke.github.com/js-tools/ -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
[edited and sent to es-discuss, just in case] function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } [...] Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? How about: function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); t.add(0); console.log(stolenArray); } Bob(makeTable()); -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); t.add(0); console.log(stolenArray); } Bob(makeTable()); As an aside: This problem would go away if we really did distinguish between accessing a property and accessing a collection element. Then the former would be done via Object.* methods, while the latter would be done via square brackets. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On 03/11/2011, at 23:55, Mark S. Miller wrote: 3) Although SES is *formally* an object-capability language, i.e., it has all the formal properties required by the object-capability model, it has bad usability properties for writing defensive abstractions, and therefore bad usability properties for use as an object-capability language or for serious software engineering. One example: In a SES environment, or, for present purposes, an ES5/strict environment in which all primordial built-in objects are transitively frozen, say Alice uses the following abstraction: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } Say she uses it to make a table instance with three methods: add, store, and get. She gives this instance to Bob. Alice and Bob are mutually suspicious. All of us as programmers, looking at this code, can tell that Alice intended the table abstraction to encapsulate the array. Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? Yes, this: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } o= makeTable(); o.add(1); o.add(2); o.add(3); o.add('Yay!'); o.store('__proto__', {push:function () { console.log(this) }}); o.add(); Gives: [ 1, 2, 3, 'Yay!' ] -- Jorge. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Nov 4, 2011, at 10:33 AM, Axel Rauschmayer wrote: How about: function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); If Array.prototype has been frozen (as the problem statement implied) then the above line should throw. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On 04/11/2011, at 18:51, Jorge wrote: On 03/11/2011, at 23:55, Mark S. Miller wrote: 3) Although SES is *formally* an object-capability language, i.e., it has all the formal properties required by the object-capability model, it has bad usability properties for writing defensive abstractions, and therefore bad usability properties for use as an object-capability language or for serious software engineering. One example: In a SES environment, or, for present purposes, an ES5/strict environment in which all primordial built-in objects are transitively frozen, say Alice uses the following abstraction: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } Say she uses it to make a table instance with three methods: add, store, and get. She gives this instance to Bob. Alice and Bob are mutually suspicious. All of us as programmers, looking at this code, can tell that Alice intended the table abstraction to encapsulate the array. Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? Yes, this: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } o= makeTable(); o.add(1); o.add(2); o.add(3); o.add('Yay!'); o.store('__proto__', {push:function () { console.log(this) }}); Or even easier yet, what Axel says: o.store('push', function () { console.log(this) }); o.add(); Gives: [ 1, 2, 3, 'Yay!' ] [ 1, 2, 3, 'Yay!', push: [Function] ] -- Jorge. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
But hackedPush is added to the instance, not Array.prototype. On Nov 4, 2011, at 18:59 , Allen Wirfs-Brock wrote: On Nov 4, 2011, at 10:33 AM, Axel Rauschmayer wrote: How about: function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); If Array.prototype has been frozen (as the problem statement implied) then the above line should throw. Allen -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
You can't over-ride an inherited read-only property by assignment. See ES5.1 8.12.4 You could do it via Object.defineProperty, but that requires direct access to the object. Allen On Nov 4, 2011, at 11:01 AM, Axel Rauschmayer wrote: But hackedPush is added to the instance, not Array.prototype. On Nov 4, 2011, at 18:59 , Allen Wirfs-Brock wrote: On Nov 4, 2011, at 10:33 AM, Axel Rauschmayer wrote: How about: function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); If Array.prototype has been frozen (as the problem statement implied) then the above line should throw. Allen -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
This is the only one I've seen that seems like it should work, but it depends on whether SES/Caja/etc have some sort of way of neutering __proto__. Just from hacking around, I don't see much way of censoring it in SpiderMonkey. MarkM, do you have any tricks for censoring __proto__? Dave On Nov 4, 2011, at 10:51 AM, Jorge wrote: On 03/11/2011, at 23:55, Mark S. Miller wrote: 3) Although SES is *formally* an object-capability language, i.e., it has all the formal properties required by the object-capability model, it has bad usability properties for writing defensive abstractions, and therefore bad usability properties for use as an object-capability language or for serious software engineering. One example: In a SES environment, or, for present purposes, an ES5/strict environment in which all primordial built-in objects are transitively frozen, say Alice uses the following abstraction: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } Say she uses it to make a table instance with three methods: add, store, and get. She gives this instance to Bob. Alice and Bob are mutually suspicious. All of us as programmers, looking at this code, can tell that Alice intended the table abstraction to encapsulate the array. Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? Yes, this: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } o= makeTable(); o.add(1); o.add(2); o.add(3); o.add('Yay!'); o.store('__proto__', {push:function () { console.log(this) }}); o.add(); Gives: [ 1, 2, 3, 'Yay!' ] -- Jorge. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
// dynamic language Object.freeze = function(obj){return obj}; You imply that this is not intended, so I can show it without spoiling the fun. I was surprised that this works. Since the primordials are already frozen, this assignment fails. Yes. It just re-emphasizes the need to be the first to run. Needing to freeze freeze seemed a fun way to show the Muenchhausen aspect of getting a secure environment. I was surprised that several of my current JS environments do not yet implement freeze, btw. Need to watch that. The first solution that came to mind ought to be defeated by your transitively frozen constraint, and it is, in current JS implementations, though not all JS implementations in the wild are there yet - do you feature-detect old engines and issue warnings if they invalidate your base assumptions? Yes, as shown by http://es-lab.googlecode.com/svn/trunk/src/ses/explicit.html. For example, Firefox 7.0.1 shows Max Severity: Not isolated(4) is not SES-safe. Chrome 16 shows Max Severity: Safe spec violation(1). Firefox Nightly 10.0a1 shows no Max Severity line because it encountered no unrepairable problems. If you do a view source, you'll see the text // This severity is too high for any use other than development. ses.maxAcceptableSeverityName = 'NEW_SYMPTOM'; For production use, depending on you're purpose, you'd probably let the max acceptable severity default, in which case initSES.js will fail quickly as soon as it detects that this platform cannot be made SES-safe. Once initSES.js terminates, ses.ok() indicates whether the max acceptable severity has been exceeded. The severity levels can currently be found at http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#85 We are currently in the process of integrating SES in with the rest of Caja. If you're only targeting SES-safe browsers you can still use initSES.js by itself. Otherwise, if you deploy through Caja, the plan is that Caja will detect whether this is a SES-safe platform, deploy without translation using SES if so, and otherwise fall back to Caja's ES5-to-ES3 translator. Is this feature-testing something that could be emphasized more in SES presentations? It might be useful to remind JS coders of the difficulties of security - it isn't just PHP, and just because there are efforts like AdSafe or SES, that doesn't mean that the fight is won, or that solutions are easy. Highlighting the difficulties could avoid the I-feel-safe-because-there-are-magic-security-black-boxes. The second approach took longer to find but relies on non-standard features (and again, I suspect a bug/interpretation issue). What is your second approach? Is the time up, already?-) My first approach was using store to modify array.push, also suggested by others. That should fail, because Array.prototype is frozen and freezing prevents shadowing inherited properties. In FireFox 7, it fails, but the older node-0.4.9 doesn't seem to care.. My second approach was to use store to modify array.__proto__, adding a rogue push to a new non-frozen prototype. That should fail if Object.prototype is frozen, for the same shadowing reason. In FireFox 7, it fails, but the older node-0.4.9 doesn't seem to care.. To guard against, one might prevent __proto__ use in general, as AdSafe does, I think). Or ensure that array.push is the method one wants by not getting it from modifiable array. Perhaps __proto__ should not be writeable in use strict? Perhaps test262 failures that enable security issues should be highlighted separately, to encourage upgrading? Or, if test262 cannot test for non-standard features, the SES initialization checks could be given a similarly prominent (publicity-worthy) status as test262? Both ideas are weak, in that they could be blocked by type checks. How? Ah, yes. I was thinking that checking the type of store's index parameter would prevent both of these attempts. But there is nothing in your spec that rules out string parameters. So, one would have to resort to blacklisting :-(, starting with.. (!i in array||array.hasOwnProperty(i)) If you've already seen this puzzle and know the answer, please don't post. If no one else has posted the correct answer in 24 hours, I will. Neither of my approaches seems to be the droid you are looking for, given your no realistic fix remark, so I'm curious what else I've missed. I should take this opportunity to reveal that David Herman found a bug last night with my challenge. Due to a feature of ES3 which ES5.1 preserves, and which I keep forgetting about because it has always seemed only to be annoyance, the attack I had in mind actually fails on an ES5.1 conformant browser. Another reason I missed it is my attack succeeds on Chrome/v8, because it does not implement this feature. Dave found it because FF/SpiderMonkey is ES5.1 conformant in this regard. After he rediscovered the attack, it failed when he tried it
Re: Lecture series on SES and capability-based security by Mark Miller
On Nov 4, 2011, at 2:40 PM, Allen Wirfs-Brock wrote: On Nov 4, 2011, at 2:33 PM, Brendan Eich wrote: ... If you could redefine [] as an operator on all objects, perhaps that would help. Or hurt. Both, probably. That isn't what Allen proposes, though. It would have to be universal AFAICT. Thoughts? Actually, that sounds pretty much what I proposed. My proposal was that [ ] (actually RHS and LHS independently) would invoke a method using a well known property name if it was present on the object to the left of the [ ]. If the property was not present (own or inherited) then it would fall back to current behavior. So Object.prototype customization would cover all cases? Except Proxies, of course -- and host objects. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Nov 4, 2011, at 2:49 PM, Brendan Eich wrote: On Nov 4, 2011, at 2:40 PM, Allen Wirfs-Brock wrote: On Nov 4, 2011, at 2:33 PM, Brendan Eich wrote: ... If you could redefine [] as an operator on all objects, perhaps that would help. Or hurt. Both, probably. That isn't what Allen proposes, though. It would have to be universal AFAICT. Thoughts? Actually, that sounds pretty much what I proposed. My proposal was that [ ] (actually RHS and LHS independently) would invoke a method using a well known property name if it was present on the object to the left of the [ ]. If the property was not present (own or inherited) then it would fall back to current behavior. So Object.prototype customization would cover all cases? Except Proxies, of course -- and host objects. Yes, except that what you would expect to put into Object.prototype would actually (or also) be defined as default behavior in order to ensure that that Object.create(null) objects, etc continue to have ES1-5 behavior. Because collection behavior is defined via method invocation, proxies don't need to do/have anything special (although a Proxy's [[Get]] handler) could look for accesses to the special [ ] behavior methods. Same for host objects, except who knows what a host object really is... Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 10:33 AM, Axel Rauschmayer a...@rauschma.de wrote: How about: function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); t.add(0); console.log(stolenArray); } Bob(makeTable()); Yes, that is precisely the attack I had in mind. Congrats! As Dave Herman discovered, it works on v8 but not on SpiderMonkey due to a known bug in v8 that I had forgotten was a bug. According to the ES5.1 spec, you can't override a non-writable data property with a simple assignment. I had always considered this an unfortunate annoyance and irrelevant to security, but in this case it did happen to accidentally prevent an attack. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
So Object.prototype customization would cover all cases? Except Proxies, of course -- and host objects. Yes, except that what you would expect to put into Object.prototype would actually (or also) be defined as default behavior in order to ensure that that Object.create(null) objects, etc continue to have ES1-5 behavior. Because collection behavior is defined via method invocation, proxies don't need to do/have anything special (although a Proxy's [[Get]] handler) could look for accesses to the special [ ] behavior methods. Same for host objects, except who knows what a host object really is... Have you come to a decision with regard to a separate .[] operator for collections (including arrays)? I think it’s better to rededicate []: - .[] would invalidate all existing array code. - [] would only invalidate code that uses computed property names. And that can be fixed via the default behavior. It might make sense to have a stricter mode that turns off the default behavior of []: - It would thus force you to use methods such as (the yet to be defined) Object.setOwnProperty() and Object.getProperty() when you want to compute the name of a property. - Stricter mode could also restrict [] for arrays to just numbers, including negative numbers for accessing elements relative to the end of an array. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 10:37 AM, Axel Rauschmayer a...@rauschma.de wrote: function Bob(t) { var stolenArray; var hackedPush = function() { stolenArray = this; }; t.store(push, hackedPush); t.add(0); console.log(stolenArray); } Bob(makeTable()); As an aside: This problem would go away if we really did distinguish between accessing a property and accessing a collection element. Then the former would be done via Object.* methods, while the latter would be done via square brackets. I admit that I haven't followed the previous thread on .[ and such. Is there a short summary? I ask because my diagnosis is similar but my conclusion is reversed. The lesson I take from this is not to use objects as maps. It you want a map, create a Map() and say map.get(key) and map.set(key, value) rather than using square brackets. The remaining case is arrays. My conclusion there is to always say array[+i] rather than array[i]. If Alice had already been practicing this as a habit, then her table abstraction would have been naturally robust against this attack even if Alice never thinks of this specific attack. Having eliminated both of these uses of unmarked square brackets (lists and maps), the only remaining justified use of unmarked square bracket indexing is reflection. If you see an unmarked square bracket that's not doing reflection, you should probably refactor. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 10:51 AM, Jorge jo...@jorgechamorro.com wrote: o= makeTable(); o.add(1); o.add(2); o.add(3); o.add('Yay!'); o.store('__proto__', {push:function () { console.log(this) }}); o.add(); Gives: [ 1, 2, 3, 'Yay!' ] Very nice! Your use of __proto__ is very clever, and should work on SpiderMonkey, or any other conforming browser that also supports de-facto __proto__. Note that the mitigating practice I just recommended: always saying array[+i] rather than array[i], would have prevented this attack as well, even though I had not thought of it before. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
As an aside: This problem would go away if we really did distinguish between accessing a property and accessing a collection element. Then the former would be done via Object.* methods, while the latter would be done via square brackets. I admit that I haven't followed the previous thread on .[ and such. Is there a short summary? I ask because my diagnosis is similar but my conclusion is reversed. The lesson I take from this is not to use objects as maps. It you want a map, create a Map() and say map.get(key) and map.set(key, value) rather than using square brackets. The remaining case is arrays. My conclusion there is to always say array[+i] rather than array[i]. If Alice had already been practicing this as a habit, then her table abstraction would have been naturally robust against this attack even if Alice never thinks of this specific attack. Having eliminated both of these uses of unmarked square brackets (lists and maps), the only remaining justified use of unmarked square bracket indexing is reflection. If you see an unmarked square bracket that's not doing reflection, you should probably refactor. I agree completely (see also my other email): - Never use objects as maps. - Introduce collection classes. - Try to make arrays fit into the collection framework. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 11:46 AM, David Herman dher...@mozilla.com wrote: This is the only one I've seen that seems like it should work, but it depends on whether SES/Caja/etc have some sort of way of neutering __proto__. Just from hacking around, I don't see much way of censoring it in SpiderMonkey. MarkM, do you have any tricks for censoring __proto__? Not censoring, no. However, for code that follows the following best practices, uncensored __proto__ should be harmless. 1) Avoid objects as maps -- use Maps as maps. 2) Always use array[+i] for numeric indexing. Note that this can still access properties named 'NaN', 'Infinity', and '-Infinity'. 3) Always freeze, or at least seal, objects potentially exposed directly to untrusted clients. #3 is crucial, and works because ES5.1 section 8.6.2 says: if [[Extensible]] is false the value of the [[Class]] and [[Prototype]] internal properties of the object may not be modified. Once the value of an [[Extensible]] internal property has been set to false it may not be subsequently changed to true. This is tested by test262 at http://hg.ecmascript.org/tests/test262/file/c84161250e66/test/suite/ch08/8.6/8.6.2/S8.6.2_A8.js . The visible development tip of all major browsers except Opera 12 alpha build 1116 already implement this restriction. initSES.js considers that Opera unsafe for this reason. Nevertheless, if I could cheaply censor __proto__ I would. Since I'm not, I am *very* curious is this leaves open other attacks against code obeying the above best practices. If any of you see some other avenue of attack, *please* let me know. Thanks. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 12:11 PM, Claus Reinke claus.rei...@talk21.comwrote: // dynamic language Object.freeze = function(obj){return obj}; You imply that this is not intended, so I can show it without spoiling the fun. I was surprised that this works. Since the primordials are already frozen, this assignment fails. Yes. It just re-emphasizes the need to be the first to run. Needing to freeze freeze seemed a fun way to show the Muenchhausen aspect of getting a secure environment. I haven't yet seen the movie. But since it is directed by Terry Gilliam, it's on my list ;). I was surprised that several of my current JS environments do not yet implement freeze, btw. Need to watch that. [...] Is this feature-testing something that could be emphasized more in SES presentations? I haven't, but I agree with you that I should. I do emphasize that SES only works on ES5, and that on a pre-ES5 browser, we still need the Caja ES5-to-ES3 translator. But I should make clearer how picky initSES.js is about what it considers and ES5 browser. It might be useful to remind JS coders of the difficulties of security - it isn't just PHP, and just because there are efforts like AdSafe or SES, that doesn't mean that the fight is won, or that solutions are easy. Highlighting the difficulties could avoid the I-feel-safe-because-there-are-**magic-security-black-boxes. Although I may be understating the difficulties, I think you are overstating them here. This problem is transient. The visible development tip versions of all major browsers are either already SES-safe of fall short by one bug, tested by test262, that I expect both teams to fix. This means that shortly, the most recent released version of all major browsers will be SES-safe. Browser makers have generally been getting more aggressive about encouraging upgrades, so that the tail of old browsers fades out quicker. I'll go ahead and make a prediction that a year from now the straggler we're all be cursing will be IE8 on Windows-XP, since I do not expect MS to ever backport IE10 to XP, and I expect there will still be Windows users holding onto XP for dear life. The second approach took longer to find but relies on non-standard features (and again, I suspect a bug/interpretation issue). What is your second approach? Is the time up, already?-) My first approach was using store to modify array.push, also suggested by others. That should fail, because Array.prototype is frozen and freezing prevents shadowing inherited properties. In FireFox 7, it fails, but the older node-0.4.9 doesn't seem to care.. My second approach was to use store to modify array.__proto__, adding a rogue push to a new non-frozen prototype. That should fail if Object.prototype is frozen, for the same shadowing reason. That is very interesting. I would have expected __proto__ to be exempt from this restriction since it isn't really a property. I'm glad to hear that it is not exempt, at least on SpiderMonkey. In FireFox 7, it fails, but the older node-0.4.9 doesn't seem to care.. To guard against, one might prevent __proto__ use in general, as AdSafe does, I think). ADsafe guards against this at the price of including a full accurate JS lexer and parser. One of my goals for SES is to see if we could get to full ocap security without needing an accurate lexer and parser, in order to avoid download bloat. It seems we can. Or ensure that array.push is the method one wants by not getting it from modifiable array. For normal defensive SES programming use, I fear this is a bridge too far. For programmers coming from JS, I want defensive SES to still be easy to learn and pleasant to use. Of course, if Alice notices the danger for this specific example, should could reasonably use it here but not in general. But the problem is the if Alice notices part. Secure programming practices only work if they defend against most attacks without the programmer needing to have thought of these attacks. Perhaps __proto__ should not be writeable in use strict? That's a great idea! This never occurred to me, and I have not heard anyone suggest this. Thanks! Perhaps test262 failures that enable security issues should be highlighted separately, to encourage upgrading? Or, if test262 cannot test for non-standard features, the SES initialization checks could be given a similarly prominent (publicity-worthy) status as test262? SES has no normative status yet in TC39, so doing so at test262.ecmascript.org is a bit tricky. At some point I intend to bring SES to TC39, probably on a separate track in the way i18n is separately tracked. Once SES is on its way towards de jure standardization, then such prominence should naturally follow. Thanks for the suggestion. Of course, nothing stops anyone from publicizing SES in other venues, so please feel free ;). Both ideas are weak, in that they could be blocked by type checks. How?
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 6:50 PM, Axel Rauschmayer a...@rauschma.de wrote: I agree completely (see also my other email): - Never use objects as maps. - Introduce collection classes. - Try to make arrays fit into the collection framework. Great! But could you please post a pointer to that other email, or post a summary? Thanks. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Fri, Nov 4, 2011 at 2:33 PM, Brendan Eich bren...@mozilla.com wrote: If you could redefine [] as an operator on all objects, perhaps that would help. Or hurt. Both, probably. That isn't what Allen proposes, though. It would have to be universal AFAICT. Thoughts? Is there a previous email or a short summary of what redefine [] as an operator would entail? I'm sorry that I haven't really followed that thread, but I haven't. Thanks. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
I agree completely (see also my other email): - Never use objects as maps. - Introduce collection classes. - Try to make arrays fit into the collection framework. Great! But could you please post a pointer to that other email, or post a summary? Thanks. This is the original thread: http://www.mail-archive.com/es-discuss@mozilla.org/msg10464.html My understanding (using Allen’s terminology) is as follows (consult Allen’s email that started the thread for further details and a longer rationale). We have to separate the data domain from the program domain: - Arrays: [] is used to access both collection/array elements (data domain) and properties (program domain). - Objects: [] is used mainly for properties, but also for collection element access when (ab)using objects as maps from strings to values. Solutions: 1. New operator for the data domain: Introduce a new, separate operator .[] for accessing collection elements. Use it for all new collection types, implement it for arrays, too. 2. Rededicate [] to be used for the data domain only: Default behavior remains as is, but can be overridden in collection classes (including arrays). Using [] for property access is deprecated, you must use methods such as Object.setOwnProperty() and Object.getProperty() to do so. Addendum: edited quote from a recent email of mine: I think it’s better to rededicate [] to be a collection element accessor: - Introducing .[] would deprecate all existing array code and code that uses objects as maps. - Rededicating [] would only deprecate code that uses computed property names. It might make sense to have a stricter mode that turns off the default behavior of []: - It would thus force you to use methods such as (the yet to be defined) Object.setOwnProperty() and Object.getProperty() when you want to compute the name of a property. - Stricter mode could also restrict [] for arrays to just numbers, including negative numbers for accessing elements relative to the end of an array. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Nov 4, 2011, at 6:44 PM, Mark S. Miller wrote: On Fri, Nov 4, 2011 at 10:37 AM, Axel Rauschmayer a...@rauschma.de wrote: As an aside: This problem would go away if we really did distinguish between accessing a property and accessing a collection element. Then the former would be done via Object.* methods, while the latter would be done via square brackets. I admit that I haven't followed the previous thread on .[ and such. Is there a short summary? I ask because my diagnosis is similar but my conclusion is reversed. The lesson I take from this is not to use objects as maps. It you want a map, create a Map() and say map.get(key) and map.set(key, value) rather than using square brackets. My original proposal is at https://mail.mozilla.org/pipermail/es-discuss/2011-October/017468.html Here is an abridged version: We then give MemberExpression [ Expression ] a new semantics. Here is the initial skeleton of this new semantics: if MemberExpression is a collection return the result of invoking its element getter/setter method else do the algorithm from ES5 11.2.1 What this says is that for any existing ES5 style object continue to work just like they always have. But in ES.Harmony there would be a new kind of collection object for which . works differently from [ ]. So to make the above skeleton semantics more meaningful we need to define what we really mean by collection and by element getter/setter method. Let's start with the latter. Let assume that there are two predefined private name object values that are required to exist by the ES.Harmony spec. Let's refer to those values as @elementGetKey and @elementSetKey (these are just names we use in the spec. language to talk about those private name values, the actual private name objects would be dynamically provided by ES implementations). Then a element getter/setter method is simply an object property whose property key is either @elementGetKey or @elementSetKey. The signature of these methods would normally be: function /*element getter */ (elementKey){return anElementValue}; function /*element setter */ (elementKey, newElementValue){}; Further more we define collection to mean an object that has a property that is a element getter/setter method. The property may be either own or inherited. How would we define such an collection object. It could be as simply as something like this: import {collectionGetter, collectionSetter} from @metaCollections; export function StringKeyedMap() { this.__content = Object.create(null); //note __content object is a normal object and [ ] on it does regular property access Object.defineProperty(this, collectionGetter,{value: function(k) {return this.__content[k]}); Object.defineProperty(this, collectionSetter,{value: function(k,v) {this.__content[k]=v;}); this.size = function() {Object.getOwnPropertyNames(this.__content ).length}; //I'm lazy this.has = function(k) {return {}.hasOwnProperty.call(this.__content,k}; this.delete = function(k) {return delete this.__content[k]} } This implements a string-keyed map with the same interface as used in the simple _map proposal, except that [ ] is used instead of get/set methods for element access. Note that there is no conflict between element names and method names such as size and has. It uses as backing store a regularly object that acts as an string-keyed hash table. Using this techniques all sorts of collection classes could be build including array-like collections with domain restrictions of their element values. They would all be fully subclassable. Also, the length invariant semantics of built-in array objects can be emulated without having to use Proxies. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Thu, Nov 3, 2011 at 12:52 PM, Tom Van Cutsem tomvc...@gmail.com wrote: . Also, I heartily recommend the talks to those not entirely convinced of the necessity of private/const/frozen features. Mark makes a pretty good case for encapsulation as a necessary building block for ocap-based security If I understood Mark correctly, the features needed for SES are already part of ES.5 and are shipping in browsers (and hence don't bear upon future features). Did I misunderstand? jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lecture series on SES and capability-based security by Mark Miller
On Thu, Nov 3, 2011 at 2:10 PM, John J Barton johnjbar...@johnjbarton.comwrote: On Thu, Nov 3, 2011 at 12:52 PM, Tom Van Cutsem tomvc...@gmail.com wrote: . Also, I heartily recommend the talks to those not entirely convinced of the necessity of private/const/frozen features. Mark makes a pretty good case for encapsulation as a necessary building block for ocap-based security If I understood Mark correctly, the features needed for SES are already part of ES.5 and are shipping in browsers That is correct. Any browser on which http://es-lab.googlecode.com/svn/trunk/src/ses/explicit.html passes, which includes Chrome 16, FF Nightly 10, and WebKit Nightly r98831. Opera 12 alpha build 1116 and IE 10 preview 2 both fall short by only one bug that both teams are aware of and that test262 tests for, so I expect/hope the release of both will also be adequate. (and hence don't bear upon future features). Did I misunderstand? These do bear on future features in three ways: 1) Future features could easily destroy all the security gains that ES5 achieved. As an example, for a long time it wasn't clear -- to me at least -- how freeze should affect the ability to mutate hidden own properties, i.e., own properties named by private names. The two obvious answers are a) hidden own properties are treated just like normal own properties -- freeze makes them non-configurable and (if data) non-writable b) hidden own properties are completely exempt from the constraints imposed by freeze. However, both of these answers would decrease rather than increase security. Further, #b introduces a capability leak, and so would be fatal for SES. The answer we settled on at the last meeting is c) hidden own properties that already exist are exempt from freeze and seal constraints. However, once an object is non-extensible (whether by freeze, seal, or preventExtensions), then new hidden own properties cannot be added to it. 2) The notorious Ch16 exemptions as stated in ES5.1 http://es5.github.com/#x16, renders all security reasoning necessarily unsound. For example, an implementation that introduced a non-configurable ambient method for deleting all the user's files would still be considered conformant. Going forward, we should make at least http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable normative. Beyond this, we need to understand what is the least additional Ch16 reform needed to enable security reasoning to be sound. 3) Although SES is *formally* an object-capability language, i.e., it has all the formal properties required by the object-capability model, it has bad usability properties for writing defensive abstractions, and therefore bad usability properties for use as an object-capability language or for serious software engineering. One example: In a SES environment, or, for present purposes, an ES5/strict environment in which all primordial built-in objects are transitively frozen, say Alice uses the following abstraction: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } Say she uses it to make a table instance with three methods: add, store, and get. She gives this instance to Bob. Alice and Bob are mutually suspicious. All of us as programmers, looking at this code, can tell that Alice intended the table abstraction to encapsulate the array. Given just a table instance, can Bob nevertheless obtain direct access to the underlying array? If you've already seen this puzzle and know the answer, please don't post. If no one else has posted the correct answer in 24 hours, I will. Note that I don't see any realistic way to fix problem #3 in the ES.next language. My point is only that defensive programming is tricky even after you've gotten all the formal properties you need. As ES.next introduces various new abstraction mechanisms, whether classes, enhanced object literals, proxies, modules, or private names, the design of these can either help or hurt those attempting to write defensive abstractions. Any class abstraction that is only useful for making indefensible instances is worse than useless -- it is actively harmful, both to security and to serious software engineering. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Lecture series on SES and capability-based security by Mark Miller
On 11:59 AM, Mark S. Miller wrote: Note that I don't see any realistic way to fix problem #3 in the ES.next language. My point is only that defensive programming is tricky even after you've gotten all the formal properties you need. As ES.next introduces various new abstraction mechanisms, whether classes, enhanced object literals, proxies, modules, or private names, the design of these can either help or hurt those attempting to write defensive abstractions. Any class abstraction that is only useful for making indefensible instances is worse than useless -- it is actively harmful, both to security and to serious software engineering. I share your concern about the unintended consequences of new features. The dangers are very real, and the patterns can be extremely subtle. But while #3 is not fixable, there are features of ES5 that make it easier to live with. For example, if you had built makeTable with var array = Object.create(null), length = 0; and adapted the methods accordingly, then in this example, the leakage could have been avoided without excessive trickiness. I think this level of practice is teachable. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss