Pages

Wednesday, February 5, 2014

CSRF/XSRF Protection in ColdFusion 9

0 comments
Here's another little thing that's come across my desk and I hope my solution can be of some help to others.

I was asked to provide a solution to protect a site from Cross Site Request Forgery (CSRF or XSRF) attacks.  Specifically, there were forms on the site that were considered at-risk for exploitation.  I won't get into great detail on what CSRF is, but basically it's an attack vector that attempts to exploit the trust that a website has in the user's browser to allow malicious actions to take place on the server.  

CF10 has methods for CSRF protection available built in, but the site I was asked to chime in on is on CF9.

So, the forms were vulnerable to a CSRF attack because a malicious user could cause a legitimate, authenticated user to unwittingly submit them.  In order to protect the public facing forms, it's necessary to set up a condition where the server can trust that the form submission is from the legitimate user during their session.  The method CF10 uses is to send a token with the form and check for it on submission.  We can do the same thing by adding just a few lines of code to our forms.

Here's a typical self-posting form:
<cfif structKeyExists(form, 'sendInfo')>
       <p>Your information has been received.</p>
    <cfelse>
      <cfform>
            <label for="fName">First name:</label><cfinput name="fName" type="text"><br>
            <label for="lName">Last name:</label><cfinput name="lName" type="text"><br>
            <input type="submit" value="Submit" name="sendInfo">
      </cfform>
    </cfif>

Let's add a token to the form that the server can check for:
<cfif structKeyExists(form, 'sendInfo')>
       <p>Your information has been received.</p>
    <cfelse>
      <cfset session.foobar = createUUID()>
      <cfform>
            <cfoutput><input type="hidden" name="foobar" value="#session.foobar#"></cfoutput>
            <label for="fName">First name:</label><cfinput name="fName" type="text"><br>
            <label for="lName">Last name:</label><cfinput name="lName" type="text"><br>
            <input type="submit" value="Submit" name="sendInfo">
      </cfform>
    </cfif>


Next, we want the form processor to check for the token:
<cfif structKeyExists(form, 'sendInfo')>    
    <cfif structKeyExists(session, 'foobar') and form.foobar is session.foobar>
       <p>Your information has been received.</p>
       <cfelse>
           <p>The form has a problem</p>
       </cfif>
    <cfelse>
      <cfset session.foobar = createUUID()>
      <cfform>
            <cfoutput><input type="hidden" name="foobar" value="#session.foobar#"></cfoutput>
            <label for="fName">First name:</label><cfinput name="fName" type="text"><br>
            <label for="lName">Last name:</label><cfinput name="lName" type="text"><br>
            <input type="submit" value="Submit" name="sendInfo">
      </cfform>
    </cfif>


And finally, we want to do a little housekeeping by dropping the token from the session when we're done with it:
<cfif structKeyExists(form, 'sendInfo')>    
    <cfif structKeyExists(session, 'foobar') and form.foobar is session.foobar>
       <p>Your information has been received.</p>
       <cfelse>
           <p>The form has a problem</p>
       </cfif>
    <cfset structDelete(session, 'foobar')>
    <cfelse>
      <cfset session.foobar = createUUID()>
      <cfform>
            <cfoutput><input type="hidden" name="foobar" value="#session.foobar#"></cfoutput>
            <label for="fName">First name:</label><cfinput name="fName" type="text"><br>
            <label for="lName">Last name:</label><cfinput name="lName" type="text"><br>
            <input type="submit" value="Submit" name="sendInfo">
      </cfform>
    </cfif>

So there ya' go.  A handful of code and you've got your server recognizing your forms for a one-time post and bouncing them on any attempted re-posting.

Continue reading →

Labels