Content Security Policy is a new browser security mechanism to prevent [cross site scripting](https://www.owasp.org/index.php/Top_10_2013-A3-Cross-Site_Scripting_(XSS\)) attacks. By sending a 'Content-Security-Policy' header in HTTP responses, web applications can provide rules and restrictions for client side scripts, plugins, frames, and other resources. Most modern browsers enforce these restrictions, preventing injection of malicious javascript, and effectively shutting down most XSS attacks.
Malcontent is a simple middleware handler for adding the CSP header to Ring applications. Simply specify a security policy as a Clojure map and malcontent will include it in responses to supported browsers.
Malcontent looks for a policy file at config/security_policy.clj
by default (but you can pass in your own path if you'd prefer). Here are the examples from the HTML5 Rocks introduction to CSP as malcontent maps:
Social media widgets:
{:sources {:script ["https://apis.google.com"
"https://platform.twitter.com"]
:frame ["https://plusone.google.com"
"https://facebook.com"
"https://platform.twitter.com"]}}
Lockdown:
{:sources {:default :none
:script "https://cdn.mybank.net"
:style "https://cdn.mybank.net"
:img "https://cdn.mybank.net"
:connect "https://api.mybank.com"
:frame :self}}
SSL Only:
{:sources {:default "https:"
:script ["https:" :unsafe-inline]
:style ["https:" :unsafe-inline]}}
In addition to sources, policy maps may include the :sandbox
and
:report-uri
directives. Sources may be specified as strings,
keywords, or vectors. Here's an example with every directive enabled:
{:sources {:default :self
:script ["https://trustedscripts.com" :unsafe-eval]
:style ["*.styles.example.com"
"https://inlinestyles.info"
:unsafe-inline]
:img "*"
:connect "https:"
:font "http://webfonts.biz"
:object :none
:media ["http://media.example.com"]
:frame :self}
:sandbox [:allow-forms
:allow-scripts
:allow-top-navigation]
:report-uri "/some/report-uri"}
Mapping CSP directives to Clojure values is simple: special values like 'self'
, 'none'
, and 'unsafe-inline'
become keywords, while sources like https:
*.example.com
and https://example.com
become strings.
To include the policy in outgoing responses, just include add-content-security-policy
as a middleware wrapper:
(ns my-great-webapp.core
(:require [malcontent.core :refer [add-content-security-policy]]))
(defroutes app-routes
(GET "/" [] my-great-request-handler))
(def app (-> routes
(add-content-security-policy)))
If you'd prefer to load the policy from somewhere besides the default location, pass it as a keyword argument:
(def app (-> routes
(add-content-security-policy :config-path "resources/policy.clj")))
For help writing a good security policy, check out the resources below.
Include malcontent as a dependency in project.clj
:
[malcontent "0.1.0-SNAPSHOT"]
- CSP Playground — interactive examples of common CSP violations and a policy validator.
- HTML5 Rocks introduction to CSP — a helpful overview of CSP use cases.
- CSP quick reference — a CSP directive cheat sheet.
- Cross-browser support — the current state of cross-browser CSP support.
- Policy recommendation bookmarklet — a one-click tool that analyzes existing pages and generates a policy recommendation.
- Automated policy generator — create a valid policy online by clicking helpful checkboxes.
- W3C CSP 1.0 specification — straight from the source.
- Map custom policies to individual routes.
- Add a default logger for policy violations.
Malcontent is released under the Apache License, v2.0. For details, see the file LICENSE.md
in this repository.