Meteor meets Mallory*Emily Stark, Meteor core [email protected]
* Mallory is usually the name of the bad guy in crypto/security stuff
Meteor security model and best
practices
Outline
1. Meteor security principles
2. Cross-site scripting
3. Mongo injections
Meteor security principles
Secure design principles
○ Data and code are separate
○ Easy to reason about client/server boundary
○ Stateful connections that must be deliberately authenticated
Securely structuring your app
○ Server code is trusted, client code is not○ server/ or Meteor.settings for secrets○ Meteor.isServer doesn't make code private
○ Use publications and allow/deny to lock down database API○ Allow/deny rules not applied to server code
Cross-site scripting
Cross-site scripting (XSS)
Cross-site scripting (XSS)
Meteor foils some attacks
< > ' " ` &
< > ' " ` &
when inside {{ }}
(packages/handlebars/evaluate-handlebars.js)
But not all
<a href="{{ userWebsite }}"> {{ username }}'s website</a>
URL sanitization
<a href="javascript:alert(localStorage)"> {{ username }}'s website</a>
URL sanitization
<a href="javascript:alert(localStorage)"> {{ username }}'s website</a>
Can you execute any damaging Javascript when quotes are escaped?
URL sanitization
<a href="javascript:eval(String.fromCharCode(77, 101, ...))"> {{ username }}'s website</a>
CSS sanitization<div style="background-color:{{ usersFavoriteColor }}"></div>
CSS sanitization<div style="background-color:expression(alert(localStorage))"></div>
Sanitize untrusted URLs and CSS
○ Don't try to filter out "javascript:", "expression", etc.
○ Do strict checking: urls start with http, css values come from a list of safe values
○ Use Content Security PolicyEx: Content-Security-Policy: default-src 'self'
Mongo injections
Mongo injections
Meteor.methods({ getUser: function(user, pwd) { return Users.findOne({ username: user, password: pwd }); }});
user: "Alice"pwd: {$ne: "foo"}
Using check
Meteor.methods({ getUser: function (user, pwd) { check(user, String); check(pwd, String); return Users.findOne({ user: user, password: pwd }); }});
check is versatile
check(usernames, [String])
check(profile, { admin: Boolean, location: Match.Optional(String)});
check(age, Match.OneOf(String, Number))
Using audit-argument-checks
Meteor.methods({ insertName: function (name) { MyCollection.insert({ name: name
}); console.log("Inserted", {name: name});
}});
insertName({ foo: "bar"})
Using audit-argument-checks
Inserted {"name": {"foo": "bar"}}insertName({
foo: "bar"})
Using audit-argument-checks
meteor add audit-argument-checksinsertName({
foo: "bar"})
Using audit-argument-checks
Inserted {"name": {"foo": "bar"}}Exception while invoking method 'insertName'Error: Did not check() all arguments during call to 'insertName'
insertName({ foo: "bar"})
What was that Meteor 0.6.4.1 release all about?
Meteor.methods({ saveUser: function(profile) { delete profile.admin; Users.insert(profile); }});
<malicious input>
{"admin": "true!", "\x01...": null, ...}
Conclusion
○ Meteor security design principles○ Securing boundary between client and server○ Data/code separation
○ Some attacks to watch out for○ Always validate untrusted user input
○ security-resources.meteor.com
Questions?
Top Related