As a developer focused consultancy, we thrive in situations where we work in new languages or try new or different things related to building apps. So when we had a chance to do some deeper security work with Clojure and specifically with Pedastal apps, we jumped at the chance.

In this post, we walk through some security points and simple libraries we built as illustrations during our discussions. They are preliminary and perhaps only proof of concept, but we thought they make an interesting and worthwhile basis for discussion.

Clojure Security Highlights

I should start by acknowledging Aaron Bedra who worked with Jemurai for a period of time and has been a valued advisor before and since then. Aaron contributed to a Clojure book and gave a talk about Clojure security that is, as far as I can tell, the only meaningful content other than this blog post on purelyfunctional.tv which in many ways takes the talk and walks through some key talking points.

At a high level, Clojure exists on top of the JVM and as such has a security profile that is closely tied to Java and the Java Library ecosystem. Things like vulnerable libraries (eg. Jetty) and deserialization / XXE apply just like they would in Java. Teams building in Clojure should use lein nvd and lein ancient to keep track of potential library issues.

We see string concatenation building queries - which should be parameterized. We see weak default output encoding in the templating language Hiccup that seems to be predominant. We also see an ecosystem that does not clearly have a way to handle security. Many common libraries are not actively maintained. As far as we could find, there is no single obvious security list for Clojure related libraries. This reflects Clojure’s position as a relatively specialized niche language.

An interesting LISP language family consideration is how code is data in Clojure and this is a positive thing (against the grain of secure design principles articulated as part of this secure design working group’s output). We need to be extremely careful with things like (read-string methods that by default will take strings and potentially evaluate them as code.

In short, all of the regular things we need to worry about with app security apply just the same to Clojure, potentially with gaps based on overall trends in popularity and maturity.

A Signal Service

We have written about building a security signal in the past. To illustrate what we are talking about, and to build, run and test a Pedastal service, we built an extremely simple proof of concept whose job is to collect signal, audit and other types of messages and forward them accordingly. It is a RESTful service that just accepts input and (currently) logs them. It could write them to syslog, elastic, or even a database table. It could be extended to multiplex based on the signal type and send Audit related messages to a different auditing subsystem.

The code boils down to this in Pedastal:

(defn signal
  [request]
  (log/error "Signal" request) ; Long run, log to DB, syslog, whatever.
  (ring-resp/response "Thank you"))  ;(:params "ya" request)))

(def common-interceptors [(body-params/body-params) http/html-body])
(def routes #{["/" :get (conj common-interceptors `home-page)]
              ["/signal" :post (conj common-interceptors `signal)]})
(def service {:env :prod
              ::http/routes routes
              ::http/type :jetty
              ::http/port 8000
              ::http/container-options {:h2c? true
                                        :h2? false
                                        :ssl? false  ; Testing.
                                        }})

All it is really doing is capturing arbitrary JSON posted to a /signal endpoint.

The full project code is available on Github at the Signal Security Service.

A Client Side Security Library

Going a level deeper, we wanted to show how you could produce security signal. What does that look like? To better illustrate that, we built a simple client library that illustrates:

  1. Doing input validation and producing security signal from it
  2. Doing auditing
  3. Testing input for obviously malicious (or scanner) payloads
  4. Sending the signal to the above service

The full detail is best found in the code and the Jemurai/seclib-clj Github Repo but here are some highlights.

Here is an example of validating a simple string and generating a signal if validation fails:

(v/validate-and-signal valid-alpha-string? "abccompany")

Here is an example of an auditable event being captured and forwarded to the signal service with tags that map it to the controls it will represent evidence for.

(signal/audit-event request "Access Control Event Message" "Tags--CIS20:17,NIST800-53:AC-4,NIST-CSF-A-D-C-AC-1")

Conclusion

I love working in Clojure. I find the LISP family to be eye opening and paradigm shifting. We have an internal code review assist tool we wrote in Clojure and hope to post about that in a subsequent Blog post - once we get it to a more publishable and usable state.

We think it is important to understand and orient to a language and the inherent risks that go along with it. Getting the opportunity to dive deeper into Clojure presented a lot of challenges but was also a lot of fun.

If you are interested in talking about Clojure and security, we’d love to chat!

References

Matt Konda

Matt is a software engineer. He's our CEO and former Chair & OWASP Board Member.

Want to stay up to date with the lastest from Jemurai?

Sign up for our monthly newsletter!