Last active
November 7, 2024 05:19
-
-
Save ProfAvery/5dbf5d1870f33d01745cc80c67b88f8a to your computer and use it in GitHub Desktop.
CPSC 455 - JavaScript prototypes, inheritance, and prototype pollution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Prototype pollution, part 1 | |
// See https://learning.oreilly.com/library/view/grokking-web-application/9781633438262/OEBPS/Text/11.html#heading_id_10 | |
const food = { | |
munch() { | |
console.log('Eating') | |
}, | |
} | |
const sandwich = { | |
__proto__: food, | |
bread: '', | |
filling: '', | |
} | |
const hotdog = { | |
__proto__: sandwich, | |
bread: 'bun', | |
filling: 'frankfurter', | |
} | |
const brainWorm = () => { | |
console.log("require('fs').rm('/', { recursive: true })") | |
} | |
console.log('food:', food) | |
console.log('sandwich:', sandwich) | |
console.log('hotdog:', hotdog) | |
hotdog.toString() // no output | |
food.toString = brainWorm | |
hotdog.toString() // oops |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Prototype pollution, part 1 | |
// See https://learning.oreilly.com/library/view/grokking-web-application/9781633438262/OEBPS/Text/11.html#heading_id_10 | |
function dangerousMerge(target, source) { | |
for (key in source) { // DON'T DO THIS | |
const value = source[key] | |
if (value instanceof Object) { | |
if (!target[key]) { | |
target[key] = {} | |
} | |
merge(target[key], value) | |
} else { | |
target[key] = value | |
} | |
} | |
} | |
// Straight from the textbook -- not actually dangerous | |
function safeMerge1(target, source) { | |
Object.entries(source).forEach(([key, value]) => { | |
if (value instanceof Object) { | |
if (!target[key]) { | |
target[key] = {} | |
} | |
merge(target[key], value) | |
} else { | |
target[key] = value | |
} | |
}) | |
} | |
// Use for...of instead of for...in | |
function safeMerge2(target, source) { | |
for (const [key, value] of Object.entries(source)) { | |
if (value instanceof Object) { | |
if (!target[key]) { | |
target[key] = {} | |
} | |
merge(target[key], value) | |
} else { | |
target[key] = value | |
} | |
} | |
} | |
const innocentUser1 = { | |
name: 'Erin', | |
address: '1234 Happy Path', | |
phone: '555-1212' | |
} | |
innocentUser2 = { ...innocentUser1 } | |
vulnerableUser = { ...innocentUser1 } | |
const attack = { | |
name: 'sneaky_pete', | |
__proto__: { | |
access_code: 'brainworms' | |
} | |
} | |
safeMerge1(innocentUser1, attack) | |
safeMerge2(innocentUser2, attack) | |
dangerousMerge(vulnerableUser, attack) | |
console.log(innocentUser1) | |
console.log(innocentUser2) | |
console.log(vulnerableUser) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes | |
personPrototype = { | |
greet() { | |
console.log(`hello, my name is ${this.name}!`) | |
}, | |
} | |
// Pass prototype to Object.create() | |
alice = Object.create(personPrototype) | |
alice.name = 'Alice' | |
alice.greet() | |
// Assign prototype to __proto__ property | |
bob = { name: 'Bob' } | |
bob.__proto__ = personPrototype | |
bob.greet() | |
// Assign prototype property of constructor function | |
function PersonFunction(name) { | |
this.name = name | |
} | |
Object.assign(PersonFunction.prototype, personPrototype) | |
charlie = new PersonFunction('Charlie') | |
charlie.greet() | |
// Use class syntax | |
class PersonClass { | |
constructor(name) { | |
this.name = name | |
} | |
greet() { | |
console.log(`hello, my name is ${this.name}!`) | |
} | |
} | |
dan = new PersonClass('Dan') | |
dan.greet() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment