LanguagesLet's Get Dangerous: Security and Sandboxing in Chrome Packaged Apps

Let’s Get Dangerous: Security and Sandboxing in Chrome Packaged Apps

Chrome packaged application provides you with the ability to access many elevated privilege only features like file access, notifications and device access. These types of elevated privileges come at a cost but there are still ways to do what you need.

Dynamic Code

When a user installs your app, they agree to give your app the elevated privileges you request. In order for Google to make sure that your app doesn’t accidently or intentionally load and run code other than what the user approved, some common JavaScript capabilities are disabled.

Eval and anything that converts a string into code can’t be run in a Chrome packaged application. This includes setTimeout, setInterval and eval. Most developers are used to calling setTimeout by passing a string to be executed.

setTimeout("MyFunction()", 1000);

You can still call setTimeout, but you will need to pass a function to it instead of a string.

setTimeout(function() { 
//Your Code
}, 1000);

Some developers are used to using eval to parse JSON from the days when this was the only way to convert a JSON structure into usable JavaScript objects. Instead of using eval, use JSON.parse(yourJsonString);.

Sandboxing

There are multiple popular frameworks that require eval to work successfully such as Kendo and Handlebars. Likewise, there are web API toolkits that rely on eval internally to work properly. In order to use these functions, you will need to put the parts of your app that need to use them in a sandbox.

To create a sandbox, modify your manifest.json file to include a “sandbox” property and under the sandbox property, create a “pages” property. The pages property takes an array of page names that you want to be sandboxed.

{
  "name": "Sandbox Example",
  "version": "0.99",
  "app": {
  "background": {
  "scripts": ["./scripts/background.js"]
  }
  },
  "icons": { "16": "icon_16.png", "128": "icon_128.png" },
  "permissions":["unlimitedStorage","storage", "https://apis.google.com/*"],
  "sandbox": {
  "pages": ["index.html"]
  }
 }

Your background.js file should open a window pointing to a file that isn’t in the sandbox, in this example, “container.html”.

chrome.app.runtime.onLaunched.addListener(function () {
  chrome.app.window.create('container.html', {
  'width': 800,
  'height': 600
  });
 });

The container HTML file is outside of the sandbox and is both restricted by the typical Chrome Packaged App restrictions and has the elevated permissions you requested in your manifest.json. In this example, the “container.html” file just contains an IFRAME that points to the “index.html” page that is in the sandbox.

<!DOCTYPE html>
 <html >
 <body>
  <iframe id="iframe" src="index.html" width="100%" height="100%" frameborder="none"></iframe> 
 </body>
 </html>

The sandboxed “index.html” page example below can not only run “loose” script in the page but can also run eval. It isn’t a complete “anything goes” environment, you still cannot use “alert” but for all intents and purposes you should be able to use any UI framework or templating library you like inside of the sandbox.

<!DOCTYPE html>
 <html >
 <head>
 <script type="text/javascript" src="./scripts/jquery-1.9.1.min.js"></script> 
 </head>
 <body>
 Frame Content <span id="OutputText"></span>
  <script type="text/javascript">
  $("#OutputText").html("What is " + eval("2+2"));
  </script>
 </body>
 </html>

Passing Messages

For most applications, you will find it easier to keep your entire UI tier inside of a sandbox page. You can use the W3C standard message API to pass messages back and forth between your sandboxed iframe and your more secure main page.

For example, if you put the script below in a script that runs on your main window, it will register a listener for “message” events. You can use these message events to receive messages from your sandboxed iframe. In this simple example, it is just passing text to output.

 $(document).ready(function () {
  window.addEventListener("message", function (event) {
  $("#MainText").html("In the main window: " + event.data.MessageText);
  });
 });

In your sandboxed page inside of the iframe, you can post a message to the non-sandboxed page by calling window.top.postMessage() API. You can pass any serializable data structure using the postMessage api; in this example it is just passing an object with a single “MessageText” property.

<!DOCTYPE html>
 <html >
 <head>
 <title>Sandbox Simple</title>
 <script type="text/javascript" src="./scripts/jquery-1.9.1.min.js"></script> 
 <link rel="Stylesheet" type="text/css" href="./css/common.css" />
 </head>
 <body>
 Frame Content <div id="OutputText"></div>
  <script type="text/javascript">
  window.top.postMessage({ MessageText: "From the sandbox" }, "*");
  </script>
 </body>
 </html>

Model-View-Controller

The security constraints put on a chrome packaged application may seem daunting at first but once you understand how sandboxing works you’ll be up and running in no time. As an added benefit of the sandboxing, it can force a cleaner separation between your UI code and your application code. The Model-View-Controller pattern is perfect in this regard.

Your sandboxed page can be responsible for displaying the user interface and routing user interaction into commands. You can then fire your commands via postMessage to your non-sandboxed app to actually interact with the data and carry out commands.

Although this is a good approach in general, as with most things in programming models there are some fuzzy areas. The Google API works by dynamically incrementally loading additional script files, which is something that can only be done inside of the sandbox. Because of this restriction, this would be an example of a scenario where using the sandbox as your “View” doesn’t necessarily keep a clean separation between your View and Controller.

About the Author:

David Talbot has over 14 years of experience in the software industry and specializes in building rich UI web applications. He is also the author of Applied ADO.NET and numerous articles on technology. He can be reached at david@legendarycode.com

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories