Slide 1

Slide 1 text

wa7son Thomas Watson wa7son github.com/watson

Slide 2

Slide 2 text

wa7son Who am I? • Thomas Watson • Principal Software Engineer at Elastic • Open Source developer at github.com/watson • Node.js Core Member • Tweets as @wa7son • Slides: github.com/watson/talks

Slide 3

Slide 3 text

wa7son JavaScript Prototypes Behind the Scenes wa7son

Slide 4

Slide 4 text

wa7son In the beginning… wa7son

Slide 5

Slide 5 text

wa7son

Slide 6

Slide 6 text

wa7son

Slide 7

Slide 7 text

wa7son

Slide 8

Slide 8 text

wa7son wa7son Classes vs Prototypes

Slide 9

Slide 9 text

wa7son Class Inheritance wa7son

Slide 10

Slide 10 text

wa7son Image - height - width - bitmap

Slide 11

Slide 11 text

wa7son Image - height - width - bitmap Button - height - width - label - onClick()

Slide 12

Slide 12 text

wa7son Button - label - onClick() Image - bitmap UIElement - height - width

Slide 13

Slide 13 text

wa7son Button - label - onClick() Image - bitmap - onClick() UIElement - height - width

Slide 14

Slide 14 text

wa7son Button - label Image - bitmap UIElement - height - width - onClick()

Slide 15

Slide 15 text

wa7son Button - label Image - bitmap UIElement - height - width ClickableElement - onClick()

Slide 16

Slide 16 text

wa7son Banana / Gorilla Problem wa7son “You wanted a banana but what you got was a gorilla holding the banana and the entire jungle” - Joe Armstrong, the creator of Erlang

Slide 17

Slide 17 text

wa7son Prototypes wa7son

Slide 18

Slide 18 text

wa7son wa7son Delegates • Shared properties / methods • Don’t find what you’re looking for on the object? Look at its prototype! • Conserve memory Prototypes

Slide 19

Slide 19 text

wa7son Java’isk Object Creation wa7son function Cat (name) { this.name = name } Cat.prototype.talk = function () { return `Meow, I'm ${this.name}!` } const whiskers = new Cat('Mr. Whiskers') whiskers.talk() // Meow, I'm Mr. Whiskers!

Slide 20

Slide 20 text

wa7son Cleaner Prototype Object Creation wa7son const proto = { talk () { return `Meow, I'm ${this.name}!` } } const whiskers = Object.create(proto) whiskers.name = 'Mr. Whiskers' whiskers.talk() // Meow, I'm Mr. Whiskers!

Slide 21

Slide 21 text

wa7son wa7son Delegates Cloning / Concatenation • Shared properties / methods • Don’t find what you’re looking for on the object? Look at its prototype! • Conserve memory • Default state / mixins Prototypes

Slide 22

Slide 22 text

wa7son Mixing it up wa7son class Image extends UIElement { // ... } const myImage = new Image() Object.assign(myImage, Clickable)

Slide 23

Slide 23 text

wa7son wa7son Delegates Cloning / Concatenation • Shared properties / methods • Don’t find what you’re looking for on the object? Look at its prototype! • Conserve memory • Default state / mixins Prototypes

Slide 24

Slide 24 text

wa7son Time to get our hands dirty… wa7son

Slide 25

Slide 25 text

{} Object Object.prototype Function Function.prototype null Object Function __proto__ __proto__ __proto__ __proto__ __proto__ prototype prototype constructor constructor constructor constructor constructor Inherited Own © Thomas Watson // @wa7son

Slide 26

Slide 26 text

{} Object Object.prototype Function Function.prototype null Object Function __proto__ __proto__ __proto__ __proto__ __proto__ prototype prototype constructor constructor constructor constructor constructor Inherited Own {} __proto__ constructor Object with custom prototype © Thomas Watson // @wa7son

Slide 27

Slide 27 text

MyObj.prototype Object Object.prototype Function Function.prototype null Object Function © Thomas Watson // @wa7son __proto__ __proto__ __proto__ __proto__ __proto__ prototype prototype constructor constructor constructor constructor constructor Inherited Own new MyObj() __proto__ constructor MyObj prototype constructor __proto__

Slide 28

Slide 28 text

wa7son Prototype Pollution wa7son

Slide 29

Slide 29 text

wa7son How to clone an object wa7son function merge (target, source) { for (const [key, value] of Object.entries(source)) { target[key] = value } return target } merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 } merge( { a: { foo: 1 } }, { a: { bar: 2 } } ) // { a: { bar: 2 } }

Slide 30

Slide 30 text

wa7son wa7son function merge (target, source) { for (const [key, value] of Object.entries(source)) { target[key] = value } return target } merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 } merge( { a: { foo: 1 } }, { a: { bar: 2 } } ) // { a: { bar: 2 } } How to clone an object

Slide 31

Slide 31 text

wa7son wa7son function merge (target, source) { for (const [key, value] of Object.entries(source)) { target[key] = value } return target } merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 } merge( { a: { foo: 1 } }, { a: { bar: 2 } } ) // { a: { bar: 2 } } ✅ ❌ How to clone an object

Slide 32

Slide 32 text

wa7son wa7son function deepMerge (target, source) { for (const [key, value] of Object.entries(source)) { if (isObject(value)) { const clone = deepMerge({}, value) if (isObject(target[key])) { deepMerge(target[key], clone) } else { target[key] = clone } } else { target[key] = value } } return target } How to deep-clone an object

Slide 33

Slide 33 text

wa7son wa7son function deepMerge (target, source) { for (const [key, value] of Object.entries(source)) { if (isObject(value)) { const clone = deepMerge({}, value) if (isObject(target[key])) { deepMerge(target[key], clone) } else { target[key] = clone } } else { target[key] = value } } return target } How to deep-clone an object

Slide 34

Slide 34 text

wa7son wa7son function deepMerge (target, source) { for (const [key, value] of Object.entries(source)) { if (isObject(value)) { const clone = deepMerge({}, value) if (isObject(target[key])) { deepMerge(target[key], clone) } else { target[key] = clone } } else { target[key] = value } } return target } How to deep-clone an object

Slide 35

Slide 35 text

wa7son wa7son function deepMerge (target, source) { for (const [key, value] of Object.entries(source)) { if (isObject(value)) { const clone = deepMerge({}, value) if (isObject(target[key])) { deepMerge(target[key], clone) } else { target[key] = clone } } else { target[key] = value } } return target } How to deep-clone an object

Slide 36

Slide 36 text

wa7son wa7son function deepMerge (target, source) { for (const [key, value] of Object.entries(source)) { if (isObject(value)) { const clone = deepMerge({}, value) if (isObject(target[key])) { deepMerge(target[key], clone) } else { target[key] = clone } } else { target[key] = value } } return target } How to deep-clone an object ✅ deepMerge( { a: { foo: 1 } }, { a: { bar: 2 } } ) // { a: { foo: 1, bar: 2 } }

Slide 37

Slide 37 text

wa7son The Attack wa7son function isAdmin (user) { return user.admin === true } const user = {} isAdmin(user) // false const payload = '{"__proto__":{"admin":true}}' deepMerge({}, JSON.parse(payload)) isAdmin(user) // true

Slide 38

Slide 38 text

wa7son The Attack wa7son function isAdmin (user) { return user.admin === true } const user = {} isAdmin(user) // false const payload = '{"__proto__":{"admin":true}}' deepMerge({}, JSON.parse(payload)) isAdmin(user) // true

Slide 39

Slide 39 text

wa7son The Attack wa7son function isAdmin (user) { return user.admin === true } const user = {} isAdmin(user) // false const payload = '{"__proto__":{"admin":true}}' deepMerge({}, JSON.parse(payload)) isAdmin(user) // true

Slide 40

Slide 40 text

wa7son The Attack wa7son function isAdmin (user) { return user.admin === true } const user = {} isAdmin(user) // false const payload = '{"__proto__":{"admin":true}}' deepMerge({}, JSON.parse(payload)) isAdmin(user) // true

Slide 41

Slide 41 text

wa7son The Attack wa7son function isAdmin (user) { return user.admin === true } const user = {} isAdmin(user) // false const payload = '{"__proto__":{"admin":true}}' deepMerge({}, JSON.parse(payload)) isAdmin(user) // true

Slide 42

Slide 42 text

wa7son wa7son • Look out for `__proto__` in untrusted user input • Look out for `constructor.prototype` in untrusted user input The Antidote

Slide 43

Slide 43 text

{} Object Object.prototype Function Function.prototype null Object Function __proto__ __proto__ __proto__ __proto__ __proto__ prototype prototype constructor constructor constructor constructor constructor Inherited Own © Thomas Watson // @wa7son

Slide 44

Slide 44 text

wa7son wa7son • Look out for `__proto__` in untrusted user input • Look out for `constructor.prototype` in untrusted user input npm install secure-json-parse The Antidote

Slide 45

Slide 45 text

wa7son wa7son The Antidote

Slide 46

Slide 46 text

github.com/watson Thank you wa7son