Blog

Mura Plugins Boot Camp: Day 4 - Security

June 4, 2015 by Grant Shepert

I said in the last blog in this series that the next post ... this one, in fact ... would be about using FW/1 as a base for plugin development. But, before we move on, I am going take a moment to talk about a very important, and sometimes overlooked, aspect of plugin development: security.

There are four areas of security we are going to look at, across two blog posts. First, we are going to ensure that the data being passed between parts of the plugin are secure, and second, we are going to make sure that the content that is being edited and rendered by the plugin has been sanitised of any potentially malicious material. Following this, we'll take a look at permissions and authentication in your plugin, and some best practices to follow when developing your plugin to ensue your plugin does not introduce any security flaws.

Form Security

Forms are a common component of a plugin, as they provide a way for users to interact with your application, but they must be integrated responsibly as they are a potential vector for somebody to compromise your system. Luckily Mura includes several ways of making this easier to do.

CSRF

Cross-Site Request Forgery is a method of altering data or functionality of a web application by manipulating the html, javascript or form processing, for instance posting to a form's end-point from an external source.

Mura has a method to counteract this type of attack:

$.renderCSRFTokens(format='form')
$.renderCSRFTokens(format='url')
$.renderCSRFTokens(format='json')

CSRF tokens add a time-based token that you can validate server-side. To validate a form, for example, simply include the renderCSRFTokens() within the form:

<form method="post" >
#$.renderCSRFTokens(format='form')#
...
</form>

This will insert a pair of time-sensitive hidden variables to the form:

<input type="hidden" name="csrf_token" value="3832B58EBFFB4E5F0A9C6658EAE922F8" />
<input type="hidden" name="csrf_token_expires" value="42157.7997917" />

When the form is posted, you simply have to call the validation routine to ensure that the tokens are valid:

if( $.validateCSRFTokens() ) {
    writeOutput("everything is good!");
}

In a JSON object, you can employ CSRF tokens like this:

<script>
    myobject=$.extend({…},#$.renderCSRFTokens(format='json')#);
</script>

This simple methodology will ensure the form content being processed on your server have come from your own forms, and not from an external source.

Content Security

There are several techniques hackers can use to break the security of your plugin. One of the most common is called Cross-site Scripting, or XSS. This is an attack where the malicious individual attempts to insert or 'inject' a custom script into your application's html or (on processing) server-side functionality. These attacks can come from a variety of sources: site visitors, infected advertisements displayed on your site, or (egads!) even internally. Thankfully there are several ways you can prevent this sort of attack. For further details, you can read up on this at OWASP.

Esapi Encoding

Lets take a look at some rendered content from my previous blog post:

<cfif structKeyExists(local.params,'myMessage') and len(local.params.myMessage)>
   <p>#local.params.myMessage#</p>
</cfif>
<cfif $.content().getValue('allowRegistration') eq true>
   <ul class="er-eventinfo">
      <li>
         <b>Attendee Limit: </b> #$.content().getValue('attendeeLimit')#
      </li>
      <li>
         <b>Location: </b> #$.content().getValue('location')#
      </li>
   </ul>
</cfif>

Nothing too complicated there, just a couple of variable being published. What if, however, somebody had managed to add a string of javascript code in the local.params.myMessage variable? Well, that string would be loaded by the browser and expose the viewer to any number of potential problems.

One of the best ways to prevent this from happening is to scrub your output so that only permitted content is allowed to be displayed. The common way of doing this is by applying an Esapi encoding filter. Mura has a built in Esapi Encoder (via the OWASP esapi encoder) that can be accessed via $.esapiEncode();. This function takes two arguments. The first is the type of encoding you want to do; typically this will be 'html' but other common ones are:

  • css, for encoding inside a style block or css template
  • html_attr, for encoding html attributes
  • url, for encoding url strings
  • javascript, for encoding inside of javascript code

You can read more about the various settings on the OWASP ESAPI site. 

The second argument passed to the function is the string you want encoded. As an example, lets take a look at how our above output would look with Esapi Encoding:

<cfif structKeyExists(local.params,'myMessage') and len(local.params.myMessage)>
   <p>#$.esapiEncode('html',local.params.myMessage)#</p>
</cfif>
<cfif $.content().getValue('allowRegistration') eq true>
   <ul class="er-eventinfo">
      <li>
         <b>Attendee Limit: </b> #$.esapiEncode('html',$.content().getValue('attendeeLimit'))#
      </li>
      <li>
         <b>Location: </b> #$.esapiEncode('html',$.content().getValue('location'))#
      </li>
   </ul>
</cfif>

Pretty easy, right? You should get into the habit of using esapi encoding where ever you are rendering variables that contain user-generated content.

Esapi and form content

You should also use Esapi Encoding when using variables passed from your forms. This will ensure that no malicious content has been inserted into the form values:

function processForm() {
   var name = $.esapiEncode('html',form.name);
}

This is a pretty simple example, but shoud illustrate how you can protect submitted form values from XSS-type attacks.

In my next post in this series, we'll take a look at authentication and permissions in your plugin, as well as an overview of some of the security features Mura incorporates that you can use in your own development.

Additional Resources

Mura CMS Documentation: Plugins http://docs.getmura.com/v6/back-end/plugins

This Mura CMS Blog entry is part of the "Mura Plugins Boot Camp" series by Grant Shepert:

Comments

Vicente Soriano

Very nice and helpful post. Thank you for sharing this, I'm starting to program plugins in MuraCMS, and the security is always something to consider (although it's commonly overlooked, as you say). The final quality depends on many things, and security is obviously one of them.

After reading your post, and test some things in my plugin, I have a question: is the esapiEncode() method accessed through the Mura Scope ($)?

The point is, I'm using it, but without the "$." prefix, and it seems to work as intended. I don't know if I have to initialize the bean differently as the documentation says. In the same documentation, it also says that you have to use the function without "$.":

http://docs.getmura.com/v6/front-end/template-variables/esapiencode/

I'm waiting to see your next security post.

Regards

-Vicente Soriano

July 9, 2015, 4:54 AM
Reply
Flag as Spam
Post a Comment

Required Field