Writing Extensions More Securely

Friday, July 22, 2011

Extensions are powerful pieces of software in modern browsers, and as such, you should help ensure that your extensions are not susceptible to security exploits. If an attacker manages to exploit a vulnerability in an extension, it’s serious business because they may gain access to the same privileges that the extension has.

The Chrome extensions system has a number of built-in protections to make it more difficult to introduce exploitable code, but certain coding patterns can still open up the risk of exploits like a cross-site scripting (XSS) attack. Many of these mistakes are common to web programming in general, so it wouldn’t be a bad idea to check out one of the many good articles on the net about XSS bugs. Here are some of our recommendations for writing healthier extensions.

Minimize your permissions

The most important thing to consider is whether you’re declaring the minimal set of permissions that you need to function. That way, if you do have a security bug in your code, the amount of permissions you’re exposing to the attacker is minimal as well. Avoid requesting (*/*) permissions for hosts if you only need to access a couple, and don’t copy and paste your manifest from example code blindly. Review your manifest to make sure you’re only declaring what you need. This applies to permissions like tabs, history, cookies, etc. in addition to host permissions. For example, if all you’re using is chrome.tabs.create, you don’t actually need the tabs permission.

Use content_security_policy in your manifest

Starting in Chrome 14, we will begin supporting Content Security Policy in extensions via the content_security_policy manifest field. This allows you to control where scripts can be executed, and it can be used to help reduce your exposure to cross-site scripting vulnerabilities. For example, to specify that your extension loads resources only from its own package, use the following policy:

"content_security_policy": "default-src 'self'"

If you need to include scripts from specific hosts, you can add those hosts to this property.

Don’t use <script src> with an HTTP URL

When you include javascript into your pages using an HTTP URL, you’re opening your extension up to man-in-the-middle (MITM) attacks. When you do so in a content script, you have a similar effect on the pages you’re injected into. An attacker on the same network as one of your users could replace the contents of the script with content that they control. If that happens, they could do anything that your page can do.

If you need to fetch a remote script, always use HTTPS from a trusted source.

Don’t use eval()

The eval() function is very powerful and you should refrain from using it unless absolutely necessary. Where did the code come from that you passed into eval()? If it came from an HTTP URL, you’re vulnerable to the same issue as the previously mentioned <script> tag. If any of the content that you passed into eval() is based on content from a random web page the user visits, you’re vulnerable to escaping bugs. For example, let’s say that you have some code that looks like this:

function displayAddress(address) { // address was detected and grabbed from the current page
eval("alert('" + address + "')");
}


If it turned out that you had a bug in your parsing code, the address might wind up looking something like this:

'); dosomethingevil();

There’s almost always a better alternative to using eval(). For example, you can use JSON.parse if you want to parse JSON (with the added benefit that it runs faster). It’s worth the extra effort to use alternatives like this.

Don’t use innerHTML or document.write()

It’s really tempting to use innerHTML because it’s much simpler to generate markup dynamically than to create DOM nodes one at a time. However, this again sets you up for bugs in escaping your content. For example:

function displayAddress(address) { // address was detected and grabbed from the current page
myDiv.innerHTML = "<b>" + address + "</b>");
}


This would allow an attacker to make an address like the following and once again run some script in your page:

<script>dosomethingevil();</script>

Instead of innerHTML, you can manually create DOM nodes and use innerText to insert dynamic content.

Beware external content

In general, if you’re generating dynamic content based on data from outside of your extension (such as something you fetched from the network, something you parsed from a page, or a message you received from another extension, etc.), you should be extremely careful about how you use it. If you use this data to generate content within your extension, you might be opening your users up to increased risk.

You can also read a few more examples of the issues discussed here in our extension docs. We hope these recommendations help you create better and safer extensions for everyone.

Post a Comment