trailhead

Secure Your Lightning JavaScript Code

Learning Objectives

After completing this unit, you’ll be able to:

  • Identify dangerous and safe JavaScript in Lightning components.
  • Use JavaScript encoding functions to protect against script injection.

Why JavaScript?

In order to enable rich interactive interfaces, Lightning lets you use JavaScript to respond to button presses and input from users and from other components. JavaScript is certainly powerful, but remember from the last unit how powerful tools affect application security: more power means more responsibility. If you’re not careful about how you use it, JavaScript creates security holes. 

We’ve discussed cross-site scripting already. Several other attacks have different effects—some even prevent a component from functioning at all. 

Here’s an example of how tricky JavaScript can be: When JavaScript code responds to events, it’s not always in the same context as it was when the event handler was registered. Sometimes the DOM or attributes of other components change between the event and the response. 

Take care when you use JavaScript, and make sure your code handles changing contexts and external circumstances. When you do it right, you create a more stable and secure component.

Asynchronous JavaScript

Asynchronous JavaScript is all the rage right now. There’s no better way to hide latency, and lots of frameworks support it. You can use asynchronous JavaScript in Lightning, but be careful with it. If you use it incorrectly, your app can crash or cause stability issues for the entire Salesforce page, not just your component.

For example, the functions setTimeout and setInterval give you access to the DOM, but accessing the DOM with these functions places them in a context outside of the Lightning framework. There are no guarantees about the parent component’s state—the function may not have a parent component at all. If the state changes, the callback function can act on data that it doesn’t own, or wait for data that never shows up. If this happens, the app throws an error message that halts the entire Salesforce page, and the component stops responding.  

If you want your function to access data in a Lightning component, you can always reach the framework with the $A.getCallback() closure. Use cmp.isValid() inside the closure to check that your component still exists.

Here’s an example.

waitAndChange: function(cmp,evt,hlp){ 
  setTimeout(function(){ 
    $A.getCallback(function(){ // access the framework in a closure 
      if(cmp.isValid()){ // does the component exist in this context? 
        cmp.set("v.resultAttr","new value");
      } 
    }); 
  },2000); 
}

This function checks that its parent component still exists before modifying its data. Without the check, an obtrusive error message prevents the user from interacting with the page.

Third-Party JavaScript Libraries

When you build a product on the Lightning platform, use only third-party libraries that work on that platform. If you use JavaScript libraries that weren’t built for Lightning, you’re asking for trouble—this code might be unreliable or unstable. 

Some libraries don’t work at all with Lightning. CKEditor is a common rich text editor package, written in JavaScript. It uses the eval function internally. We discussed in the first unit how LockerService improves stability and security by disallowing calls to eval in Lightning. As a result, CKEditor doesn’t work with LockerService. 

When you’re shopping for third-party libraries, look for those that work with Lightning, and especially with LockerService. You can find out more about our supported libraries on our developer blog post.

Event Handling

Event-driven programming is similar to asynchronous programming, but Lightning handles event response somewhat differently. In standard web development, you use regular JavaScript functions like this one to register an event handler. 

<a href="#" onclick="javascript:myFunction()">Click me</a>

LockerService disables inline JavaScript, so you have to rely on the Lightning controller to handle events for you. Specifically, you define a method on the controller, and then pass that method in a Lightning expression to register your event handler.

<a href="#" onclick="{!c.myFunction}">Click Me</a>

Controller.js

myFunction: function(cmp, evt, hlp){ 
  alert('button clicked');
}

Process Data Securely with JavaScript

When we develop apps, we often make assumptions about the data in our systems. For example, we assume that phone numbers are numeric with punctuation and names are alphabetic. When our code enforces these assumptions, we ensure the data is used correctly. 

Other times, your data needs to be processed in a specific way before it’s used. For example, HTML markup and CSS styling both need to be treated specially in code. For this, we use encoding.

Encoding

Sometimes you have to place data into a potentially dangerous context. In this case, you can encode that data so that it is manifestly safe in that context. 

You can learn more about encoding schemes and encoding contexts in the Injection Vulnerability Prevention module.  

Let’s look at an example.

<aura:unescapedHTML value="{! '<b>'+v.userInput+'</b>'}"/>

Here we render some user input as raw HTML. In this scenario, we need to use raw HTML because we added our own markup to the user data. As we discussed earlier, this tag leaves the application vulnerable to attack. For example, if the user enters “<plaintext>”, everything following this string shows up as text characters, even existing HTML code.

Salesforce provides a package called secure-filters, which includes a set of filters that transforms data so that it always displays as text regardless of context. secure-filters automatically encodes characters that are dangerous in HTML. Thus transformed, the dangerous tag delimiters “<” and “>” become the harmless literals “&lt;” and “&gt;”, which are displayed as text by an HTML parser. This is a nice way of neutralizing nasty HTML code.

Note

Note

The secure-filters package doesn’t validate input—it only sanitizes output.

Now let’s learn how to embed these filters into your project and see how to use them. This step has already been completed for you in the “SecureFilters Demo” in our Kingdom Management developer org.

  1. Identify a Lightning component that can benefit from the encoding functions in secure filters.
  2. In your developer org, open the Developer Console and create a new static resource named securefilters with MIME Type: text/javascript.
  3. Click Submit.
  4. In a new browser tab, open the secure filter file on GitHub: /lib/secure-filters.js.
  5. View the raw code and copy or download it, then paste the code into your “securefilters” static resource.
  6. In the Lightning component you identified in step 1, add the following markup wherever you want to use the filters.
<ltng:require scripts="{!$Resource.securefilters}" />

To use the filters, call secureFilters.FILTERNAME(UNTRUSTED_DATA) in your JavaScript code, such as your component's controller or helper. For example, if you have a dynamic CSS object (unsafeCss) that you want to render as text (safeCss), here’s how you do it:

safeCss = secureFilters.css(unsafeCss); // Use safeCss.

Let’s see the filters in action. We’re going to revisit our mythical creatures from the previous unit.

  1. In your Kingdom Management developer org, on the left side of the navigation bar, click App Launcher, then select the Secure Lightning app.
    App Launcher screenshot
  2. Navigate to the SecureFilters Demo tab.
  3. You see a page that lists mythical beasts. Search for “wyvern.”
    • The result is what we saw when we first looked at the unescapedHTML example. Let’s search for our friend the Balrog again.
  4. Search for “Balrog.”
    • On cue, the Balrog gives its battle cry, and text in the Balrog’s description rotates around the screen. Now we’re going to neutralize the Balrog by transforming its description to plain text.
  5. Open the code in an editor:
    1. Open the Developer Console under the quick access menu ( Settings screenshot).
    2. Select File | Open Lightning Resources.
    3. Choose LTNG_SecureFilters_Demo and click Open Selected. 

Look at the component markup for the creature’s description by clicking on LTNG_SecureFilters_Demo.cmp from the menu in the developer console. We’ve already imported DemoSecureFilters and secureFilters.html, and encoded the record name as secure HTML. If we encode the description as HTML, the Balrog’s battle cry cannot move text around, and our page is safe. Here’s the simple fix:

outputT += "Description: " + secureFilters.html(results[i].Description__c) + "<br />";

There are secure filters for many types of data, including HTML, CSS, and JavaScript. Check out the Resources section for more information.

Now that we’ve talked about securing the code in each of your components, let’s see how Lightning maintains their state. We also show how we can get components to interact securely on the Lightning platform.

Resources

Modifying Components Outside the Framework Lifecycle

Secure filters library

Client Side Rendering to the DOM

Note

Note

Remember, this module is meant for Lightning Experience. When you launch your hands-on org, switch to Lightning Experience to complete this challenge.

retargeting