Skip to main content
March 22, 2016
Mobile

Keeping your Hosted Web App secure



Hosted Web Apps running on Windows 10 benefit from the web platform improvements and updates implemented in Microsoft Edge, the default bowser of Windows 10. That same web platform and its new rendering engine also power Hosted Web Apps.

When it comes to security, this means that developers can use familiar techniques to secure the web content of their Hosted Web App. In other words, the same tools developers would use to secure their apps in the browser can also secure their Hosted Web Apps.

On top of those familiar security features, however, Hosted Web Apps also have a few additional ones to help keep the app secure.

Content Security Policy

When it comes ensuring your web content is kept safe, you have Content Security Policy (CSP). CSP lets you to create a list of sources of trusted content, and instructs the browser to only execute or render resources from those sources. In the context of Hosted Web Apps, CSP can be used to keep the users of your apps protected from cross-site scripting (XSS) on the web.

Why do I need CSP?

You need CSP because the web and its security model are based on the same origin policy concept, under which the browser will permit scripts contained in a web page to access data in another web page but on the condition that both of these web pages have the same origin. That origin is defined as a combination of URI scheme, hostname, and port number.

Primarily, this important security mechanism of same origin policy prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page’s Document Object Model (DOM). Each origin is kept isolated from the rest of the web, giving developers a safe sandbox in which to build and play.

In layman’s terms: script or code from “https://myweb.com” should only have access to “https://myweb.com’s data, and “https://malicious.com” should not be allowed access. If this wasn’t in place, “https://malicious.com” could attack “https://myweb.com” by injecting some harmful script. This injection attack is called cross-site scripting (XSS).

To help reduce these XSS risks and data injection attacks on modern browsers, W3C’s Web Application Security Working Group came up with the Content Security Policy security layer. CSP achieves this by declaring the dynamic resources that are allowed to load or pass in the Content-Security-Policy HTTP header.

This declarative policy enables you to give the browser a whitelist of locations from which it can load resources from and tell it whether the browser can use inline styles or scripts and dynamic JavaScript evaluation. If there’s an attempt to load a resource from somewhere that isn’t on this whitelist, loading of that resource is blocked.

By default, CSP assumes an opt-in policy. Hence, if you don’t declare otherwise, all inline <style> and <script> tags are blocked.

The HTTP header will look something like:

[code language=”csharp”]

Content-Security-Policy: directive;

[/code]

CSP 1.0 includes the following options for directives:

  • default-src:
  • script-src
  • object-src
  • style-src
  • img-src
  • media-src
  • frame-src
  • font-src
  • connect-src

For example, the following declaration would ensure that all content comes only from the site’s own origin domain:

[code language=”csharp”]

Content-Security-Policy: default-src ‘self’;

[/code]

This example, on the other hand, allows content from a trusted domain and all of its subdomains, even if it differs from the domain on which the CSP is set:

[code language=”csharp”]

Content-Security-Policy: default-src ‘self’ *.mydomain.com

[/code]

The above examples show how you can deliver CSPs via an HTTP header. However, you can set a policy directly in the markup of a page using meta tags. The following example shows a meta tag with an http-equiv attribute specifying a CSP:

[code language=”csharp”]

<meta http-equiv="Content-Security-Policy" content="default-src https://mytrsuteddomain.com; child-src ‘self’;">

[/code]

As mentioned earlier, Hosted Web Apps are powered by Microsoft Edge’s web platform and thus rely on its implementation of this policy. As per the latest platform status on Edge’s Dev Center page, Microsoft Edge build 10240+ implements Content Security Policy (CSP) 1.0.

1_csp

If you would like to view the Content-Security-Policy implementation on the domain that you are loading into the Hosted Web App, you can use the developer tools on Edge: run the app from Visual Studio and then press F12, which will pop up the F12 Developer Tools. From there, go to “Network” and view the response headers of the calls.

The following screenshot from a sample debugging session shows the CSP applied when the web application tries to load some content from Facebook.

2_FB

For Hosted Web Apps, you can declare a list of allowed/trusted resources/URIs in the Application Content URI Rules (ACURs), which in turn gives remote URLs direct access to Universal Windows Platform (UWP) APIs from remote HTML, CSS, and JavaScript.

CSP also enables you to lock down the page if, for example, you would like to ensure that only the resources written by you get loaded.

A good approach when setting up security is to start with the most restrictive CSP as a default, which will block just about everything using the directive default-src ‘none’, and from there, add any allowed resources (e.g. scripts, images, CSS styles, frames).

In summary, CSP helps you create a safer environment to run scripts (e.g. yours or trusted third parties) against hardware APIs provided by the Universal Windows Platform (UWP).

As a best practice, Microsoft strongly recommends that developers creating Hosted Web Apps apply CSP on any page that will have access to UWP APIs, keeping your app and users safe and away from cross-site scripting harm.

Content URI rules and Scope

The web is full of hyperlinks that take us from one site to another without much thought. It’s actually one of the things that makes the web so great—it’s linkable!
Content URI rules are a part of Hosted Web Apps to provide additional security. They do this by limiting the “scope” of the web app. Only domains or URLs listed in the Content URI rules will be viewed within the Hosted Web App. Other linked pages will be seen as part of the web (and outside the app) and be opened in the default browser.

Building with Visual Studio

If you are using Visual Studio, you’ll set these rules in the manifest under a tab labeled “Content URIs.”

3_contentURIs

You can list a particular URL or a domain in this list, then set them to “include” to have them included in the app scope or “exclude” to have them considered out of scope. All URLs or domains not in the list are considered out of the application scope.

Building with command line tools

If you’re building your app with command line tools, use the “scope” attribute to set the application scope:

[code language=”csharp”]

{ …
"scope": "https://app.mydomain.com/"

}

[/code]

The “scope” attribute is often good enough for most web apps, but if you find you need to list more than one domain or URL, then you’ll also want to include the ManifoldJS-specific “extended scope” to expand on what the W3C scope enables”:

[code language=”csharp”]

{

"scope": "https://app.mydomain.com/",
"mjs_extended_scope:[
"https://video.mydomain.com", "https://music.mydomain.com"
]

}

[/code]

The Content URI rules are also used to determine the API access for each URI. For security reasons, you only want to enable Windows API access on pages that you trust.

There are two levels of API access you can provide. The first is “allow for web only,” which enables only APIs created by the addWebAllowedObject API. This access allows you to expose particular UWP or custom APIs into your Hosted Web App and does not give your URI access to the entire UWP API surface. The second option is “all,” which allows access to the entire UWP API surface, including APIs exposed through addWebAllowedObject.

Enabling access to these APIs in Visual Studio is again done through the Content URI rules. You simply set the level for each domain or URL.

4_setalevel

Your default value for each URI is “none.”

If you’re using ManifoldJS to build your app with the command line tool, you’ll do this via the API access value.

[code language=”csharp”]

{

"mjs_api_access": [
{ "match": "https://app.mydomain.com/", "access": "allowForWebOnly", "platform": "windows10" }
]

}

[/code]

You can set multiple rules for different URIs. If you want to enable API access for everything in your scope, you can pass a wildcard to the value:

[code language=”csharp”]

{

"mjs_api_access": [
{ "match": "*" }
]

}

[/code]

Keep in mind, ManifoldJS builds apps for all platforms, so the rules will apply to all platforms unless a specific platform is specified. You can read more about this topic on the wiki for ManifoldJS.

Maximizing security with Webviews and iframes

It’s a general rule of thumb to use an iframe when content is “known” and then to use a WebView for everything else. It’s important to remember that, in a Hosted Web App, you have access to an iframe at any time, as well as access to a WebView when you have enabled the UWP APIs on a page.

Remember that any URL loaded in an iframe must meet these two qualifications:

  1. URLs must be HTTPS
  2. URLs must be listed in Content URIs (application scope)

If a page doesn’t meet those qualifications, then it will not load in the iframe. This can be helpful in locking down content where you know what URLs should be loaded, and trust that if any other URL tries to load in your iframe, it will be rejected by the app.

Additionally, same-origin and window.postmessage() rules work just as they do in a browser. If your app is dealing with content that falls under the “unknown” category, then you’ll want to use a WebView to load this portion of content (keep in mind you can use a WebView inside the Hosted Web App).

By default, the WebView will have no access or knowledge of the parent page and will only have access to UWP APIs if they are enabled in the Content URIs for that specific domain or URL. However, you can still communicate back and forth between a WebView and the parent page through specified APIs, such as invokeScriptAsync and window.notify.

WebViews are generated in the DOM as an HTML tag:

[code language=”csharp”]

<x-ms-webview src="https://www.mydomain.com"></x-ms-webview>

[/code]

The WebView can then be controlled like any other page element. It can be accessed via JavaScript and stylized via CSS.

Conclusion

A wise man once said “with great power comes great responsibility.” The same goes for Hosted Web Apps. With a Hosted Web App, your app can access UWP APIs from Bluetooth to users’ “contacts” and everything in between, and it is critical to keep your app secure. With Hosted Web Apps, you have every tool you need to do so.

Additional resources

Be sure to check out the other posts in our series:

Written by Jeff Burtoft (@boyofgreen), Principal Program Manager for TED Services & Devices, and Rami Sarieddine, Senior Tech Evangelist for Windows & Web