On Using the Latest Version of AntiSamy with ColdFusion
In ColdFusion applications, I tend to use the AntiSamy Java library to sanitize user-supplied input. While updating to the latest version of AntiSamy (actually, the snapshot of an upcoming release - more on that later) I documented the process, and particularly how Maven can make it easier.
For a few years the OWASP AntiSamy project appeared to be strictly in maintenance mode, but development has been very active over the past two years, with 12 releases since March 2020. Reading the release notes reveals that these are not just updating vulnerable dependencies (including log4j), but also valuable improvements, such as schema validation for policy files and reducing the risk of reverse tabnabbing via the adddition of
rel="noopener" to anchors when
target="_blank" is set. All good reasons to stay current!
The basic process of using Antisamy with ColdFusion varies, depending on if you're using Adobe ColdFusion or Lucee. I'll cover some of the differences later. Regardless, we need to get the AntiSamy jar file, along with all of its dependencies, and load them into our application.
This is relatively painless and totally worth it if you're looking to integrate Java projects with a ColdFusion application. There are any number of guides for installing Maven, but the official install guide is probably a good place to start. To quote their docs:
The installation of Apache Maven is a simple process of extracting the archive and adding the
binfolder with the
mvncommand to the
Maven is also available via Homebrew and MacPorts for macOS and Chocolatey for Windows (though I've never tried any of those approaches). You'll know you're good to go when you can run the
mvn --version command in your terminal.
Getting the Jars You Need
We're going to use the AntiSamy project on GitHub to build the jars that we need. As we'll see later on, this will also enable us to build the jars for any version we want, even if hasn't been released yet. So, let's hop into the command line and get started.
Download the project from GitHub:
git clone firstname.lastname@example.org:nahsra/antisamy.git
Change directories into the project:
We're on the
mainbranch now. We could build here, but it's probably better if we checkout a specific release tag before building, so that we know exactly what we're getting. The following command will list the tags, with the most recent first:
git tag -n --sort=-creatordate
At the time I'm writing this, the most recent release is
v1.6.6, so we'll check out the code there:
git checkout v1.6.6
This will result in a warning that
You are in 'detached HEAD' state.- this is fine - we're not making changes, we're building a version.
Time to build our AntiSamy jar:
Maven will do its thing, running tests, compiling dependencies, etc. At the end we should get the message:
If you open it up the project a file manager, you'll see that it has a new
/targetdirectory, in which you will find the newly built
Now, if you've worked with AntiSamy before, you know it has a handful of dependency jars. Where are those? We don't have them yet, but it's just one more Maven command to get them:
mvn dependency:copy-dependencies -DincludeScope=runtime
Note that the last option there,
-DincludeScope=runtime, is so that we only get the production dependencies and not those that are only needed for testing.
After running that command you'll find all the dependency jars within
That's it, we've got the latest AntiSamy jar and its up-to-date dependencies.
Building a Fat Jar
A brief detour - while we're having fun with Maven, it's interesting to see what else we can do. This section is not necessary for using AntiSamy with ColdFusion - it's just taking a look at an alternative approach to jar building.
Instead of having the AntiSamy jar and its dependencies separate, we can instruct Maven to build a "fat" or "uber" jar - that is, a single jar that contains both AntiSamy and all of its dependencies. Note that this does involve editing the project's
pom.xml, but it's a minor change.
Using your favorite code editor, open the AntiSamy
pom.xml file. If you're using VS Code, you can just run
code pom.xml from the project root.
Locate the top level
<plugins> block, within the
<build> section. Note that this is following the
<pluginManagement> block, not within it. In
v1.6.6 it begins on line 218. At the top, we'll add a new
<plugin> node for the current version of the Maven Assembly Plugin:
<!-- within <plugins> -->
<!-- I placed it above the maven-clean-plugin plugin -->
After saving the file, hop back to the command line. Here, we'll run the following command, which will delete the existing
/target directory and then rebuild the jar, using the updated
mvn clean package
Again, Maven will test, assemble, and build, outputting a lot of information to the console, finally culminating with a
BUILD SUCCESS message.
With that, you'll find the fat jar (AntiSamy + dependencies) in the
/target directory, named
antisamy-1.6.6-jar-with-dependencies.jar. You can load that single jar into your ColdFusion application, rather than having to load up AntiSamy and its seventeen dependencies separately.
Loading AntiSamy Into Your CFML Application
Rather than clutter this blog post with extensive code blocks, I've put together a repository on GitHub with demo code of loading AntiSamy into both Lucee and Adobe ColdFusion applications. If the following sections of this post are confusing, hopefully the full code examples there help clarify things!
If you're using Lucee, the process of loading the AntiSamy jars into your application is straightforward. You pass them, as an array of file paths, into
this.javaSettings.loadPaths in your
Application.cfc. You'll then be able to use
createObject to access and use AntiSamy.
Adobe ColdFusion Approach
Here, wiring up AntiSamy is a little more complicated, but doable, nonetheless.
Issue 1: For reasons that I don't understand, Adobe ColdFusion does not play nice with loading the AntiSamy jars via
this.javaSettings. The solution, as detailed by none other than Ben Nadel, is to use Mark Mandel's JavaLoader Project.
Issue 2: Additionally, Adobe ColdFusion does not play nice with the implementation of SLF4J (a logging library) that ships with AntiSamy. The solution, also thanks to Ben Nadel, is switch SLF4J to a no-operation implementation, which is done by adding one more dependency jar: SLF4J NOP Binding. This can be done manually, but we'll use Maven, since its been the focus of this post. By making one small change to AntiSamy's
pom.xml, we can instruct Maven to use SLF4J's no-operation jar. This is done by changing the
artifactId of SLF4J from
slf4j-nop within its
<dependency> block (around line 109 at the time of writing):
After saving this change to the
pom.xml, we need to clean out and rebuild the jars. We can run the following command, to clean, rebuild, and download production dependencies, all at once:
mvn clean package dependency:copy-dependencies -DincludeScope=runtime
And like that, you'll have the jars you need to use AntiSamy with Adobe Coldfusion. For the specifics of the implementation, head on over to the demo repository on GitHub.
Coda: On the Benefits of Testing
Remember how, in the first paragraph, I said that I ended up using a snapshot of the upcoming release? Here's where I finally get around to explaining why.
Before updating the jars, I wanted to make sure that there were no changes in functionality that would break my application. While this particular app's code coverage is nowhere near 100%, I'm working to improve that, and this was a great opportunity to add a few more tests. So, using TestBox, I built out some specs and expectations for AntiSamy's functionality within the project.
And here's where tests saved the day. When I updated AntiSamy to 1.6.5 (the version when I started writing this post), the tests failed. Specifically, an error message that was expected was not getting returned. This lead to me open an issue on the AntiSamy repository, and it turned out that there was actually a bug with the latest release - 1.6.5 was not returning CSS errors like it should have!
The 1.6.6 release on April 2 included a fix for the issue (along with security fixes and an enhancement).
Looking at the date of the issue I opened, I'm realizing it was over a month ago, and this post has taken quite a while to write, so I'm going to wrap it up. Bottom line, adding tests, even incrementally, can be surprisingly valuable to an application.
See the section "Using Third Party Java Libraries (Jar Files) in CFML" section on CFDocs if you're unfamiliar with this approach. ↩︎
I should note that recent versions of Adobe ColdFusion have built-in support for much of AntiSamy's functionality, via
isSafeHTML. However, there are still reasons you might want to use the jars directly, rather than the built-in functionality - these include access to the latest updates, the ability to return invalid HTML error messages, and dual-CFML-platform support (Lucee and Adobe). ↩︎
To be clear, this means that SLF4J/AntiSamy discards all logging. Now, logging isn't a terribly important part of the AntiSamy project, but it is used to warn about the use of features that are deprecated. ↩︎