Recently, I had reason to do a bit of research on Cross Site Scripting (XSS) and how it affects Meteor. This is what I found out – I hope this information will help you, too. First, let’s understand what XSS is.
XSS can be caused by the response generated either by the Server or in the Client with the dynamic content generation. Since Meteor does not do Server Side Rendering yet, we will focus on Client Side XSS.
As an example, let’s say I’m working on a community forum site with Meteor that allows users to post links. One of the typical templates looks like this:
This seems perfectly fine. But, let’s say someone adds a post with URL
When you click that link, you’ll see the alert box as shown below.
The older version of the Telescope Meteor app is also vulnerable to this hack and has avoided it with something like this:
This is just one type of XSS attack. To learn more, consult the OWASP XSS guide.
This is the most important question. Of course, simply posting an alert message, as in the example above, would not do any harm.
XSS mostly occurs when your app accepts and displays user generated content. But XSS can still happen even if you are not accepting any user generated content.
So, it’s better to take any measures you can to prevent XSS and related attacks.
The OWASP XSS guide shows some untrusted areas in the HTML where you might need to focus when adding user content. If your app uses one of those areas, use some defense mechanism to deal with XSS.
Even if you have made sure to cover all the untrusted code shown above, there is still a chance that you might miss some places.
Sometimes a package you install or a third party library can cause vulnerability to XSS or might do something unintended.
That’s where the W3C standard, Content Security Policy, comes in handy. With CSP, a web server can ask the browser to limit some of the actions that cause XSS.
Click here learn more about CSP directives.
Meteor has a package called
browser-policy, which helps you to create CSP rules very easily.
Once you add the package, you will get the following CSP policies by default.
default-src 'self'; script-src 'self' 'unsafe-inline'; connect-src * 'self'; img-src data: 'self'; style-src 'self' 'unsafe-inline';
This is how we can interpret the above rules, in plain text:
These restrictions add some level of protection, but the third and fourth points make your app still vulnerable to XSS.
Add the following code in the server side of your app to remove potential vulnerabilities:
Adding this code will prevent you from using Meteor’s DDP connection, so you should also add the following rules:
var rootUrl = __meteor_runtime_config__.ROOT_URL; BrowserPolicy.content.allowConnectOrigin(rootUrl); BrowserPolicy.content.allowConnectOrigin(rootUrl.replace('http', 'ws'));
If you are hosting on meteor.com, you need to add rules like the ones shown below. This is not an ideal solution, since your app is allowed to connect to any app hosted on meteor.com.
Since we blocked all the origins, you will need to allow resources as shown below. Adding something like Google Analytics is tricky, since you need to expand its asynchronous code and allow it to run without inline scripts and eval.
To do this, first add the following code inside the HTML head:
Now create a file called
ga.js into your public folder and add following content:
ga("create", "YOUR_GA_ID", "YOUR_WEBSITE"); ga("send", "pageview");
Finally, add the following CSP permissions:
//for the script BrowserPolicy.content.allowScriptOrigin("*.google-analytics.com"); //for the tracking pixel BrowserPolicy.content.allowImageOrigin("*.google-analytics.com");
Since we blocked inline scripts, Fast Render won’t work. I’ve already decided on a fix and I plan to release it in the next week.
Although CSP saves us from XSS, browser extensions can defeat CSP. Refer to this article for more information about this. Although it’s not something we should worry much about, it is possible to completely turn off CSP from a browser extension.
Unfortunately, Chrome does not show these modified headers in its developer console. Instead it shows the original headers. Because of this, detecting these kinds of issues is very hard. Since these extensions are installed by the user, we can’t do much about it.
In this post I’ve covered XSS basics and how XSS can be prevented with Meteor. I’ve also talked about Content Security Policy and how you can implement CSP with Meteor, along with some other facts. I hope this information is useful for you as you work on improving your app’s security. I’ll post more security related topics in upcoming weeks.