NOTE: ColdFusion 10+ has native support for several encoding methods that are built on top of the OWASP libraries. encodeForHTML() for example. The following post was mostly a fun exploration of dynamic programming.
The Open Web Application Security Project (OWASP) maintains a project called the Java Encoder. The Java Encoder is a high-performance encoder class that encodes String values for "safe use" in different contexts. In a Java project, this encoder is dead-simple to use. However, in a ColdFusion project, care has to be taken when invoking the methods since the method signatures all require the use of javaCast() in order to ensure java.lang.String inputs.
My OWASP Encoder.cfc project is a light-weight ColdFusion component wrapper for the Java Encoder class that takes care of all of the javaCast() invocation for you. The Encoder.cfc implements all of the same top-level .forCONTEXT() methods. These methods can accept any "simple value" (number, string, date, boolean, etc.), and will javaCast() the input to a String internally, invoke the proxied method, and return the result.
To see this in action, let's instantiate the proxy and run a "problematic" string value through each encoding method:
As you can see, the Encoder.cfc takes an instance of the Java Encoder class to proxy. Then it exposes all of the same top-level methods. And, when we run this code, we get the following output:
forCDATA --- You & me are "cool" <Truth />!
forCssString --- You \26 me are \22 cool\22 \3cTruth \2f\3e!
forCssUrl --- You\20\26 \20me\20 are\20\22 cool\22 \20\3cTruth\20\2f\3e!
forHtml --- You & me are "cool" <Truth />!
forHtmlAttribute --- You & me are "cool" <Truth />!
forHtmlContent --- You & me are "cool" <Truth />!
forHtmlUnquotedAttribute --- You & me are "cool" <Truth />!
forJava --- You & me are \"cool\" <Truth />!
forUri --- You%20&%20me%20are%20%22cool%22%20%3CTruth%20/%3E!
forUriComponent --- You%20%26%20me%20are%20%22cool%22%20%3CTruth%20%2F%3E%21
forXml --- You & me are "cool" <Truth />!
forXmlAttribute --- You & me are "cool" <Truth />!
forXmlComment --- You & me are "cool" <Truth />!
forXmlContent --- You & me are "cool" <Truth />!
What's really cool is that I didn't have to hand-write each of these methods. Since the method signature is exactly the same for each method - it takes a simple value and returns a string - I was able to employ some dynamic ColdFusion programming.
All I did was create a private method that would inspect its own name at runtime using the getFunctionCalledName() function. It would then use the dynamically-bound name to turn around and invoke the appropriate method on the Java Encoder. In the end, all I had to do was write this one method and then point all of the public method references to it:
I love how dynamic ColdFusion is - so freakin' badass. I thought about trying to implement this using closures that would dynamically bind a function instance to an encoder method name. But, using getFunctionCalledName() felt like a cleaner and easier to read solution.
Want to use code from this post? Check out the license.