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.
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.
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 AuditA cyber security audit is an independent evaluation of an organization's information systems, policies, and procedures to assess their compliance with relevant security standards and regulations. The audit typically involves a thorough review of the organization's security and risk management processes, and incident response plans, as well as an assessment of its ability to prevent, detect, and respond to cyber threats. 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.
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:
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")
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!