Bypassing Package-Based Basic Auth

Written by Pete Corey on Mar 28, 2016.

In a previous post, I talked about using Basic Authentication to hide your Meteor application from prying eyes. Unfortunately, the most straight-forward way of implementing this kind of protection has its flaws.

To see those flaws, let’s imagine that we’ve set up a basic Meteor application with the kit:basic-auth package and a Meteor method:

Meteor.methods({
  foo: function() {
    return "bar";
  }
});

When we try to navigate to the application (http://localhost:3000/), we notice that we can’t access the application without valid credentials. Great!

Bypassing Basic Auth

However, Jesse Rosenberger recently pointed out that kit:basic-auth, and similar packages such as jabbslad:basic-auth, do not provide Basic Auth protection for WebSocket connections. This means that any external user can easily bypass this authentication mechanism and access your Meteor methods and publications.

For example, an external user could connect directly to your application using Meteor’s DDP API and call your "foo" method:

var connection = DDP.connect("http://localhost:3000/");
connection.call("foo", function(err, res) {
  console.log(res);
});

Any unauthorized user that runs the above code will receive a result of "bar" from the "foo" method.

This is a bad thing.

Calling In the Dark

While the DDP API gives users access to all of your Meteor methods and publications, it doesn’t reveal those methods and publications. In order to call a method or subscribe to a publication, a user needs to know its name.

However, this kind of security through obscurity shouldn’t be considered any real protection. An attacker eager to discover your DDP endpoints could build a brute forcer that guesses method and publication names in an attempt to uncover your endpoints.

A Better Basic Auth

At first glance, the kit:basic-auth and jabbslad:basic-auth packages seem to be doing all the right things. They’re injecting the Basic Auth check as a piece of connect middleware at the head of the stack which, in theory, should catch all HTTP traffic and verify the user’s credentials.

Unfortunately, the Meteor framework establishes the socket connection long before any of these middleware methods are called. This means that Basic Auth is ignored during the WebSocket handshake and upgrade process.

One possible technique for overcoming this middleware issue is to “overshadow” all "request" and "upgrade" listeners and inject our Basic Auth check there. The Meteor framework does this exact thing to support raw WebSocket connections.

However, a more straightforward approach to this problem may be to move your application behind a proxy such as HAProxy, or NGINX and implement Basic Auth at that level. The proxy would protect all assets and endpoints, including the /sockjs/.../websocket endpoint, which is used to establish a WebSocket connection with the server.

Final Thoughts & Thanks

I’d like to give a massive thanks to Jesse Rosenberger who pointed out this issue to me, and gave me a huge amount of very helpful information and observations.

I’d also like to apologize to anyone hiding applications behind a package-based Basic Auth guard based on my advice. I’ve updated my previous post on this subject to reflect what I’ve learned and pointed out the current shortcomings of this package-based approach.

NoSQL Injection in Modern Web Applications

Written by Pete Corey on Mar 21, 2016.

Last month I was lucky enough to be able to attend and speak at the first ever Crater Remote Conference!

I gave a talk entitled “NoSQL Injection in Modern Web Applications”. The talk was heavily focused on exploiting NoSQL injection vulnerabilities in applications using MongoDB. The bulk of the talk was spent in a hands-on demo showing how a malicious user could approach and attack a Meteor application vulnerable to these types of attacks.

Check out a recording of the presentation below, and be sure to watch a few of these highlights!

02:41 - Why security?
04:57 - What is “NoSQL Injection”?
12:25 - Grabbing all products by exploiting a publication.
17:36 - Getting all carts by exploiting a publication.
20:20 - Getting all carts through a .findOne query.
23:42 - Removing all user carts in the system.
25:26 - Modifying product prices.
29:40 - Escalating myself to admin level permissions.
34:55 - MongoDB denial of service through a .find query.
38:55 - How do we fix it?
42:30 - Why pick on MongoDB?
44:10 - Are other NoSQL databases safe?
47:40 - Q&A with Josh Owens.

At the end of the talk, I linked to Rob Conery’s Meteor Shop. You may also be interested in his fantastic PluralSight course on building the application from the ground up.

I also linked to my own package, Check Checker (east5th:check-checker), which helps you find methods and publications within your Meteor application that aren’t being thoroughly checked.

I had a blast watching the Crater Conf talks this year, and I’m looking forward to the next conference!

Stored XSS and Unexpected Unsafe-Eval

Written by Pete Corey on Mar 14, 2016.

In a previous post, I discussed the possibility of exposing Cross Site Scripting (XSS) vulnerabilities in your Meteor application through the use of jQuery components.

I gave an example where a malicious string with a <script> tag was being injected into the DOM through a call to $.html. For example:

$(...)
  .html("");

My recommendation in that post was to sanitize the string with Blaze._encode before injecting it into the DOM.

Another potential solution to this problem is to use the browser-policy Meteor package to establish a Content Security Policy (CSP) within your application. However, this solution comes with its share of quirks.

When CSP Falls Short

A Content Security Policy is used to tell the browser, among other things, what types of Javascript is allowed to run within a client’s browser, and what should be blocked.

Many applications instruct their Content Security Policy to disallow inline scripts (unsafe-inline). Inline scripts refer to any javascript that executes within an HTML element’s event handler attributes, within a <script> tag, or through the URL with a javascript: protocol.

It may seem like disallowing inline scripts would prevent our Cross Site Scripting issue. After all, the malicious Javascript is running from an inline <script> tag that’s being injected into the DOM.

However, in the eyes of the Content Security Policy, a <script> tag injected through a call to $.html is not considered an inline script.

Unexpected Unsafe-Eval

If your Content Security Policy disallows inline scripts, but allows Javascript evaluation (unsafe-eval), your application would still be vulnerable to this particular type of Cross Site Scripting attack.

Under the hood, this after-the-fact injection of a <script> tag, and its subsequent execution is considered an eval statement. Only by disallowing unsafe-eval can you prevent this type of XSS attack.

This is incredibly unintuitive and may lead to dangerous misunderstandings about what types of Javascript your application is allowed to execute. For a variety of reasons, some applications require the use of unsafe-eval. Without understanding the subtleties of what is considered an eval by your Content Security Policy, you may be vulnerable to severe Cross Site Scripting attacks.

It’s important to remember that a Content Security Policy is not a panacea against all front-end attacks. Instead, it’s a helpful safeguard that can be used in conjunction with other safeguards like properly sanitizing data, and validating user input.